@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  --glass-bg: rgba(255,255,255,0.55);
  --glass-bg-strong: rgba(255,255,255,0.72);
  --glass-border: rgba(255,255,255,0.85);
  --text-light: #1a1a1a;
  --text-light-secondary: #5c5c5c;
  --text-light-muted: rgba(26,26,26,0.45);
  --active-bg: #1a1a1a;
  --active-text: #ffffff;
  --moss: #1a1a1a;
  --moss-dark: #000000;
  --clay: #a8532f;
  /* Accent system — per-page.
     The DEFAULT below is neutral: Home and Account run with no accent
     colour at all, so every "accent" resolves to the existing black/grey
     and those pages look exactly as they did before any of this.
     Studio and Pricing opt in by putting a theme class on <body>.

     Because every accent rule in this file reads these four tokens and
     never a literal colour, switching a page's palette is one class —
     there's no second set of rules to keep in sync. */
  --accent: #1a1a1a;
  --accent-deep: #000000;
  --accent-soft: rgba(26,26,26,0.06);
  --accent-softer: rgba(26,26,26,0.04);
  --accent-line: rgba(26,26,26,0.18);

  --radius-lg: 20px;
  --radius-md: 14px;
}
/* Home — cyan.
   The pure neon #04D9FF is 1.7:1 on white, which is why it read as
   "not showing up" — borders and labels in it were nearly the same
   luminance as the page. The neon is kept where it works (the tint
   fill, where it's a wash rather than a line) while borders and text
   step down to values that are actually visible. Same colour family,
   still reads as electric cyan. */
body.theme-blue {
  --accent: #06B6D4;
  --accent-deep: #0E7490;
  --accent-soft: rgba(4,217,255,0.16);
  --accent-softer: rgba(4,217,255,0.09);
  --accent-line: rgba(6,182,212,0.55);
}

/* Pricing — neon pink #FE019A. Only 3.69:1 on white, which is fine for
   borders, fills and large/bold text but FAILS AA for small text. So
   --accent-deep is a darkened version of the same hue (5.78:1) and is
   what any small text resolves to — that's why the two tokens differ
   more here than they do on the slate theme. */
body.theme-pink {
  --accent: #FE019A;
  /* Was #C4017A. Now the neon throughout — labels sit at 3.15:1 on the
     tint rather than 4.92:1. */
  --accent-deep: #FE019A;
  --accent-soft: rgba(254,1,154,0.14);
  --accent-softer: rgba(254,1,154,0.06);
  --accent-line: rgba(254,1,154,0.35);
}

/* Account — mint green. Light and fresh; the deeper variant carries
   labels so they remain legible on the tint. */
body.theme-green {
  --accent: #34D399;
  --accent-deep: #0E7C5A;
  --accent-soft: rgba(52,211,153,0.18);
  --accent-softer: rgba(52,211,153,0.09);
  --accent-line: rgba(52,211,153,0.6);
}

/* Studio, Projects and Render History — peach.
   Warmer and lighter than the previous #EA580C. Borders use the peach
   itself; labels step to a deeper terracotta so they stay readable
   against the tint. */
body.theme-peach {
  --accent: #FF8A5B;
  --accent-deep: #BF5A33;
  --accent-soft: rgba(255,138,91,0.18);
  --accent-softer: rgba(255,138,91,0.09);
  --accent-line: rgba(255,138,91,0.6);
}

* { box-sizing: border-box; }
html, body { min-height: 100%; }
body {
  margin: 0;
  font-family: 'Inter', -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  color: var(--text-light);
  position: relative;
  /* Faint pastel blur backdrop — soft blue/lavender, green, and yellow/pink
     tones blended together, kept light so glass panels and text stay
     clearly legible on top. */
  background:
    radial-gradient(ellipse 70% 60% at 15% 15%, #daeaf9 0%, transparent 55%),
    radial-gradient(ellipse 65% 55% at 85% 10%, #d9f2d9 0%, transparent 55%),
    radial-gradient(ellipse 70% 60% at 80% 85%, #fcf2d1 0%, transparent 55%),
    radial-gradient(ellipse 60% 55% at 20% 90%, #fbe0e9 0%, transparent 55%),
    #fbfbfa;
  background-attachment: fixed;
  min-height: 100vh;
  overflow-x: hidden;
}
body::before, body::after {
  content: "";
  position: fixed;
  border-radius: 50%;
  filter: blur(120px);
  z-index: 0;
  pointer-events: none;
}
body::before {
  top: -20%; left: -15%; width: 560px; height: 560px;
  background: radial-gradient(circle, #cfe4f7 0%, transparent 70%);
  opacity: 0.5;
}
body::after {
  bottom: -20%; right: -15%; width: 600px; height: 500px;
  background: radial-gradient(circle, #f8e8b8 0%, transparent 70%);
  opacity: 0.4;
}
main::before {
  content: "";
  position: fixed;
  top: 30%; left: 40%;
  width: 420px; height: 260px;
  border-radius: 50%;
  background: radial-gradient(circle, #f3d6e0 0%, transparent 70%);
  filter: blur(130px);
  opacity: 0.3;
  z-index: 0;
  pointer-events: none;
}
header, main { position: relative; z-index: 1; }

header {
  padding: 20px 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Anchor for the centred nav tabs below. */
  position: relative;
}
/* Hairline dividing the header (logo, nav, account/login) from the page.
   Drawn as a pseudo-element inset from the edges rather than a plain
   border-bottom, so it stops short of the viewport sides and reads as a
   rule under the content rather than a hard band across the window.
   Very low opacity — it should register as a seam, not a border. */
header::after {
  content: "";
  position: absolute;
  left: 32px;
  right: 32px;
  bottom: 0;
  height: 1px;
  background: rgba(26,26,26,0.09);
  pointer-events: none;
}
@media (max-width: 560px) {
  header::after { left: 16px; right: 16px; }
}
header .titles { display: flex; align-items: center; gap: 14px; }
header .titles h1 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: 0.02em; color: var(--text-light); }
header .titles p { margin: 3px 0 0; color: var(--text-light-secondary); font-size: 13px; }
header h1 { margin: 0; font-size: 19px; font-weight: 600; color: var(--text-light); }
header p { margin: 3px 0 0; color: var(--text-light-secondary); font-size: 13px; }

.account-nav { display: flex; align-items: center; gap: 14px; font-size: 13px; }
/* Home / Render / Projects / Account are centred in the header itself,
   not centred within whatever space is left over beside the logo. Using
   flex alone would shift them whenever the logo or the Login/Logout
   label changed width (e.g. "Login" vs "Logout", or the credit badge
   growing from "2 CREDITS" to "100 CREDITS"). Absolute centring pins
   them to the true middle of the page regardless. pointer-events is
   restored on the tabs themselves so the transparent gap either side
   doesn't swallow clicks meant for the header beneath. */
@media (min-width: 861px) {
  .nav-tabs {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
  }
  .nav-tabs > * { pointer-events: auto; }
}
.credit-badge {
  background: none;
  border: none;
  color: var(--text-light);
  /* Metrics deliberately identical to .studio-tab. */
  padding: 8px 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.01em;
  transition: background .15s ease, transform .18s ease, box-shadow .18s ease;
  /* Now a real <a> tag (was a <span>) so it's a genuine, keyboard-native
     link to /account.html#plan-section — reset the browser's default
     link styling (blue color, underline) since this should look and
     behave like the pill badge it always was, not a text link. */
  display: inline-block;
  text-decoration: none;
  cursor: pointer;
}
.credit-badge:hover {
  background: rgba(255,255,255,0.9);
  /* Previously background-only, which barely registers against a light
     hero background (see the "Sign Up — 2 Free" state) — every other
     button on the site lifts and casts a shadow on hover, so this now
     matches. Only `background` gets overridden per credit-tier below;
     transform/box-shadow here still apply on top of every tier. */
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0,0,0,0.12);
}
.credit-badge:active {
  transform: translateY(0);
  box-shadow: 0 1px 4px rgba(0,0,0,0.10);
}
/* Color scale reflects how much of the plan's monthly allocation is left
   (green = plenty, red = nearly/fully spent) rather than a flat on/off
   "you're out" state — the badge stays informative the whole way down,
   not just at zero. */
.credit-badge.tier-green { background: rgba(76,187,23,0.14); border-color: rgba(76,187,23,0.4); color: #2d7a0d; }
.credit-badge.tier-lime { background: rgba(168,217,72,0.2); border-color: rgba(168,217,72,0.5); color: #6b8f1a; }
.credit-badge.tier-yellow { background: rgba(245,226,122,0.3); border-color: rgba(245,226,122,0.65); color: #8a7112; }
.credit-badge.tier-orange { background: rgba(240,160,61,0.16); border-color: rgba(240,160,61,0.5); color: #b5651d; }
.credit-badge.tier-red { background: rgba(229,38,43,0.14); border-color: rgba(229,38,43,0.45); color: #c41e24; }
.credit-badge.tier-green:hover { background: rgba(76,187,23,0.22); }
.credit-badge.tier-lime:hover { background: rgba(168,217,72,0.3); }
.credit-badge.tier-yellow:hover { background: rgba(245,226,122,0.42); }
.credit-badge.tier-orange:hover { background: rgba(240,160,61,0.24); }
.credit-badge.tier-red:hover { background: rgba(229,38,43,0.22); }
/* When the "Get more" pill is showing, the badge loses its right-side
   rounding so the two read as one continuous button, per the reference. */
.credit-badge.attached { border-radius: 20px 0 0 20px; border-right: none; }
.get-more-pill {
  background: #1a1a1a;
  color: #fff;
  border-left: 1px solid var(--glass-border);
  padding: 8px 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-decoration: none;
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
}
.get-more-pill:hover { background: #333; transform: translateY(-1px); box-shadow: 0 3px 10px rgba(0,0,0,0.20); }
.get-more-pill:active { transform: translateY(0); box-shadow: 0 1px 4px rgba(0,0,0,0.16); }
.account-nav a { color: var(--text-light-secondary); text-decoration: none; text-transform: uppercase; letter-spacing: 0.02em; font-size: 12px; font-weight: 600; }
.account-nav a:hover { color: var(--text-light); }
.account-nav button.nav-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--text-light-secondary);
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.account-nav button.nav-button:hover { color: var(--text-light); }
.account-nav a:focus-visible,
.account-nav button.nav-button:focus-visible,
.credit-badge:focus-visible {
  outline: 2px solid var(--moss);
  outline-offset: 2px;
  border-radius: 4px;
}

.logo-link {
  display: inline-block;
  text-decoration: none;
  color: inherit;
  border-radius: 6px;
}
.logo-link:hover .logo-img { opacity: 0.7; }
.logo-link { transition: opacity .15s ease; }
.logo-link:focus-visible {
  outline: 2px solid var(--moss);
  outline-offset: 3px;
}
.logo-img { height: 20px; width: auto; display: block; }

.link-muted { color: var(--text-light-secondary); text-decoration: none; transition: color .15s ease; letter-spacing: 0.01em; }
.link-muted:hover { color: var(--text-light); text-decoration: underline; }
.link-accent { color: var(--moss-dark); font-weight: 600; text-decoration: none; transition: color .15s ease; letter-spacing: 0.01em; }
.link-accent:hover { color: #000; text-decoration: underline; }

.secondary-btn {
  padding: 0 20px;
  background: rgba(255,255,255,0.5);
  color: var(--text-light);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  letter-spacing: 0.01em;
  transition: background .18s ease, border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
/* The light-button counterpart to .generate — same lift-and-settle
   mechanics, softer shadow so it stays secondary to the black button
   sitting next to it. Covers Cancel, Close, See More, Share, etc. */
.secondary-btn:hover:not(:disabled) {
  background: rgba(255,255,255,0.85);
  border-color: rgba(26,26,26,0.22);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0,0,0,0.12);
}
.secondary-btn:active:not(:disabled) {
  transform: translateY(0);
  box-shadow: 0 1px 4px rgba(0,0,0,0.10);
}
.secondary-btn:disabled { opacity: 0.5; cursor: not-allowed; }

.nav-tabs { display: flex; gap: 8px; }
.nav-tab {
  display: inline-block;
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 12px;
  font-weight: 700;
  padding: 8px 16px;
  border-radius: 20px;
  border: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.4);
  color: var(--text-light);
  transition: background .15s ease, color .15s ease;
}
/* (a) Menu items had a near-invisible background tint and nothing else.
   Now they darken, lift and cast a shadow — the same acknowledgement
   every other control on the site gives the cursor. */
.nav-tab:hover {
  background: rgba(255,255,255,0.92);
  border-color: rgba(26,26,26,0.22);
  color: var(--text-light);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0,0,0,0.10);
}
.nav-tab:active { transform: translateY(0); box-shadow: 0 1px 4px rgba(0,0,0,0.10); }
.nav-tab:focus-visible { outline: 2px solid rgba(26,26,26,0.55); outline-offset: 2px; }
.nav-tab.active { background: var(--active-bg); color: var(--active-text); border-color: transparent; }
button.nav-tab { font-family: inherit; cursor: pointer; }
/* The current page still responds, but keeps its black fill so the
   "you are here" marker never reads as unselected mid-hover. */
.nav-tab.active:hover {
  background: #000;
  border-color: transparent;
  color: var(--active-text);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
}

/* The `hidden` attribute must actually hide things.
   Browsers implement it as `[hidden] { display: none }` in the user-agent
   stylesheet, which ANY author rule that sets `display` overrides — and
   `main { display: grid }` immediately below does exactly that. The result
   was that the Studio's History and Projects panels ignored their `hidden`
   attribute entirely and rendered stacked underneath the Render tab, so
   the section tabs appeared to do nothing. !important is warranted here:
   `hidden` is a statement of intent from the markup and should not be
   silently defeated by an unrelated layout rule. */
[hidden] { display: none !important; }

main {
  /* width:100% is load-bearing, not decorative. body is a flex column
     (for the sticky footer), and an auto margin on the cross axis
     overrides align-self:stretch — the element then sizes to fit-content
     and centres. That made every page as wide as whatever happened to be
     inside it: the Projects tab collapsed to a sliver, Render sat
     mid-width, Render History was widest. Setting width:100% restores
     "fill the row, then cap at max-width". */
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  box-sizing: border-box;
  padding: 36px 24px 48px;
  display: grid;
  gap: 16px;
}
main.app-layout {
  max-width: 1180px;
  padding-top: 6px;
  grid-template-columns: 420px 1fr;
  align-items: stretch;
  gap: 20px;
}
.app-left { display: grid; gap: 16px; }
.app-right {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* Its own pane again, sitting below the Preview card. margin-top:auto
   pushes it to the bottom of the right column so its lower edge lines up
   with the bottom of the stacked panes on the left, rather than floating
   directly under the preview with dead space beneath. */
/* Sits directly beneath the Preview card with the column's normal gap.
   margin-top:auto was pushing it to the bottom of the right column,
   which left a large dead gap whenever the preview was shorter than the
   stacked panes on the left. */
#actionsBlock {
  flex-shrink: 0;
  min-height: 68px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.actions-placeholder { text-align: center; color: var(--text-light-muted); font-size: 12.5px; }
/* Same reasoning as .output-placeholder above. */
.output-frame + p, #outputBlock > p { font-size: 11px; }
.output-frame {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: rgba(255,255,255,0.3);
  border: 1px solid var(--glass-border);
  /* Landscape by default; JS then sets this to the actual image's own
     aspect ratio once a render loads (see setOutputFrameRatio). */
  aspect-ratio: 16 / 10;
  width: 100%;
  max-height: 560px;
  flex-shrink: 0;
}
.output-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-light-muted);
  padding: 40px;
  text-align: center;
}
.output-placeholder i { font-size: 40px; }
/* Matched to the body text in the left-hand panels (Drop an image here,
   etc.) — this column was reading a size larger than everything beside
   it, which made the two columns look like different designs. */
.output-placeholder p { margin: 0; font-size: 12.5px; }
/* The slider fills the frame; a plain single <img> result stays centered. */
.output { position: absolute; inset: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.output > .ba-slider { align-self: stretch; flex: 1 1 auto; height: 100%; }
.output img { width: 100%; height: 100%; object-fit: contain; border-radius: var(--radius-md); border: none; }

@media (max-width: 860px) {
  main.app-layout {
    grid-template-columns: 1fr;
    max-width: 500px;
  }
}

/* Tablet / large phone — the full header (logo + 4 nav tabs + login/logout
   + credit badge) needs ~640px and overflows every iPhone size, so from
   here down the nav moves to its own row beneath the logo instead of
   fighting for space alongside it. */
@media (max-width: 820px) {
  header {
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 20px;
  }
  .account-nav {
    width: 100%;
    justify-content: flex-start;
    flex-wrap: wrap;
    row-gap: 8px;
    gap: 10px;
  }
  .nav-tabs { flex: 1 1 auto; }

  /* "Render another" / "Share" / "Download" side-by-side gets tight well
     before 480px — three labeled buttons with icons need real width.
     Stack them from here down so each stays comfortably tappable. */
  #postGenerateActions { flex-direction: column; }
  #postGenerateActions > * { width: 100%; }
}

@media (max-width: 480px) {
  header {
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 20px;
  }
  .account-nav {
    flex-wrap: wrap;
    row-gap: 8px;
    width: 100%;
    justify-content: flex-start;
  }
  /* The four tabs together need ~348px and won't fit an iPhone SE's ~280px
     of usable width. Rather than wrapping into a ragged two-row block,
     they scroll horizontally as one tidy row — a familiar mobile pattern,
     and it keeps every tab the same height and reachable. Tabs shrink
     slightly too so most phones show all four without needing to scroll. */
  .nav-tabs {
    flex: 1 1 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 6px;
    padding-bottom: 2px;
  }
  .nav-tabs::-webkit-scrollbar { display: none; }
  .nav-tab {
    padding: 9px 13px;
    font-size: 11.5px;
    white-space: nowrap;
    flex: 0 0 auto;
  }
  .credit-badge {
    padding: 9px 13px;
    font-size: 11.5px;
    white-space: nowrap;
  }
  main, main.app-layout {
    padding-left: 16px;
    padding-right: 16px;
  }
  #postGenerateActions {
    flex-direction: column;
  }
}

/* Very narrow phones — trim padding a touch further so all four tabs
   have the best chance of fitting without scrolling at all. */
@media (max-width: 360px) {
  .nav-tab { padding: 9px 11px; font-size: 11px; letter-spacing: 0.02em; }
  .credit-badge { padding: 9px 11px; font-size: 11px; }
  header { padding: 14px 16px; }
}

.glass-shell {
  background: var(--glass-bg);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.08);
}

.label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-light-secondary);
  margin: 0 2px 8px;
}
.label-toggle {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  font-family: inherit;
}
.label-toggle i { font-size: 14px; transition: transform .15s ease; }
.label-toggle.open i { transform: rotate(180deg); }

/* mode dropdown */
.mode-select { position: relative; }
.mode-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: rgba(255,255,255,0.55);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 13px 14px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-light);
  text-align: left;
  transition: background .15s ease;
}
/* Thin dark outline on hover so these read as interactive fields, not
   static text. Applies to both the Input mode picker and the Project
   selector, which share this class. */
.mode-trigger { transition: background .15s ease, border-color .15s ease; }
.mode-trigger:hover {
  background: rgba(255,255,255,0.75);
  border-color: rgba(26,26,26,0.45);
}
.mode-trigger .placeholder { color: var(--text-light-muted); font-weight: 400; }
.mode-trigger i { font-size: 16px; color: var(--text-light-secondary); flex-shrink: 0; transition: transform .15s ease; }
.mode-trigger.open i { transform: rotate(180deg); }

.mode-panel {
  display: none;
  margin-top: 8px;
  background: rgba(255,255,255,0.85);
  backdrop-filter: blur(28px);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 6px;
  max-height: 340px;
  overflow-y: auto;
}
.mode-panel.open { display: block; }

.mode-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border: none;
  border-radius: 10px;
  background: transparent;
  color: var(--text-light);
  cursor: pointer;
  text-align: left;
}
.mode-row:hover { background: rgba(26,26,26,0.06); }
.mode-row .icon { font-size: 17px; color: var(--text-light-secondary); flex-shrink: 0; width: 18px; text-align: center; }
.mode-thumb {
  width: 36px;
  height: 36px;
  border-radius: 8px;
  flex-shrink: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.45);
  border: 1px dashed rgba(26,26,26,0.2);
}
.mode-thumb.has-image { border-style: solid; border-color: var(--glass-border); }
.mode-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mode-thumb i { font-size: 16px; color: var(--text-light-muted); }
.mode-row.selected .mode-thumb { border-color: rgba(255,255,255,0.4); background: rgba(255,255,255,0.15); }
.mode-row.selected .mode-thumb i { color: rgba(255,255,255,0.7); }
.mode-row .texts { flex: 1; min-width: 0; }
.mode-row .texts strong { display: block; font-size: 13.5px; font-weight: 500; }
.mode-row .texts span { display: block; font-size: 11px; color: var(--text-light-secondary); margin-top: 1px; }
.mode-row.selected { background: var(--active-bg); color: var(--active-text); }
.mode-row.selected .icon { color: var(--active-text); }
.mode-row.selected .texts span { color: rgba(255,255,255,0.75); }

.example-toggle {
  background: none;
  border: none;
  color: var(--moss-dark);
  font-size: 10.5px;
  font-weight: 600;
  cursor: pointer;
  padding: 2px 0 4px 44px;
  text-decoration: underline;
  display: block;
  transition: color .15s ease;
}
.example-toggle:hover { color: #000; }
.example-pair {
  display: none;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin: 0 0 6px 44px;
}
.example-pair.visible { display: grid; }
.example-pair img { width: 100%; height: 70px; object-fit: cover; border-radius: 8px; border: 1px solid var(--glass-border); }
.example-pair .ex-label { font-size: 9px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-light-muted); text-align: center; margin: 2px 0 0; }

/* upload dropzone */
.upload-zone {
  border: 1.5px dashed rgba(35,41,31,0.3);
  border-radius: var(--radius-md);
  padding: 34px 20px;
  text-align: center;
  cursor: pointer;
  background: rgba(255,255,255,0.25);
  transition: border-color .15s ease, background .15s ease;
}
.upload-zone:hover, .upload-zone.dragover { border-color: var(--moss); background: rgba(255,255,255,0.4); }
.upload-zone i.upload-icon { font-size: 30px; color: var(--text-light-secondary); }
.upload-zone .drop-title { margin: 10px 0 2px; font-size: 14px; font-weight: 500; color: var(--text-light); }
.upload-zone .drop-sub { margin: 0; font-size: 12px; color: var(--text-light-secondary); }
.upload-zone.has-image { padding: 0; border-style: solid; overflow: hidden; background: none; }
.upload-zone img { max-width: 100%; max-height: 260px; display: block; margin: 0 auto; border-radius: 12px; }
input[type="file"] { display: none; }

/* notes stacked above the render button, roomy enough for the full 100-word limit */
.notes-col { display: flex; flex-direction: column; gap: 8px; }
.notes-optional { font-weight: 400; color: var(--text-light-muted); }
.notes-toggle-chevron { transition: transform 0.2s ease; }
.notes-toggle-chevron.flipped { transform: rotate(180deg); }

/* Collapsed by default (max-height: 0, clipped) rather than display:none,
   so open/close animates smoothly instead of jumping. */
.notes-expanded {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  width: 100%;
  box-sizing: border-box;
  transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease;
}
.notes-expanded.open {
  max-height: 420px;
  opacity: 1;
  margin-top: 10px;
  overflow-y: auto;
}
/* Borderless once expanded — sits directly in the panel rather than
   looking like its own separate boxed field, matching the plain-text
   entry feel requested rather than the bordered-box look every other
   input on this page has. */
.notes-textarea-borderless {
  border: none;
  background: transparent;
  padding: 4px 2px;
}
.notes-textarea-borderless:focus { outline: none; }
/* Notes uses .mode-trigger for its collapsed state (so it already gets
   the outline above); this covers the expanded textarea so the field
   still responds once opened. */
.notes-expanded { transition: border-color .15s ease; }
.notes-textarea-borderless { transition: background .15s ease; }
.notes-textarea-borderless:hover:not(:focus) { background: rgba(255,255,255,0.45); }
textarea {
  width: 100%;
  box-sizing: border-box;
  display: block;
  min-height: 150px;
  padding: 14px;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.6;
  resize: none;
  overflow-y: hidden;
  background: rgba(255,255,255,0.55);
  color: var(--text-light);
}
.notes-counter {
  width: 100%;
  box-sizing: border-box;
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--text-light-muted);
  text-align: right;
}
.notes-counter.limit { color: var(--clay); }
textarea::placeholder { color: var(--text-light-muted); }
textarea:focus, .upload-zone:focus-visible, .mode-row:focus-visible, .mode-trigger:focus-visible {
  outline: 2px solid var(--moss);
  outline-offset: 1px;
}

/* The single black-button style for the whole app. Every dark button
   (Render, Save profile, Download, Load past renders, plan CTAs) uses
   this class, so changing it here changes all of them consistently —
   sentence case rather than uppercase, one font stack, one hover. */
.generate {
  flex-shrink: 0;
  padding: 0 26px;
  background: var(--moss);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  letter-spacing: 0.01em;
}
/* More visible than the old background-only shift: lifts slightly and
   casts a shadow, so the button clearly responds to the cursor. */
.generate:hover:not(:disabled) {
  background: var(--moss-dark);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(0,0,0,0.22);
}
.generate:active:not(:disabled) {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
}
.generate:disabled { background: rgba(35,41,31,0.2); color: rgba(35,41,31,0.4); cursor: not-allowed; }
/* Destructive variant — identical shape, size and hover mechanics to the
   standard black button, just red, so it sits with its neighbours while
   still reading as dangerous. Inline background needs !important to beat
   the base .generate:hover rule. */
#deleteAccountBtn:hover:not(:disabled) { background: #a93226 !important; }
#generateBtn { padding-top: 16px; padding-bottom: 16px; font-size: 15px; }
/* Pink only while it can actually be pressed. A disabled button keeps the
   muted grey it already had — colouring it would advertise an action
   that isn't available, which is worse than it being plain. */
#generateBtn:not(:disabled) {
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-deep);
}
#generateBtn:not(:disabled):hover {
  background: var(--accent-softer);
  border-color: var(--accent);
}

.status { font-size: 12.5px; color: var(--text-light-secondary); margin: 8px 2px 0; min-height: 18px; }
.status.error { color: var(--clay); }



/* Inline "this will use N credits" confirmation for expensive (4K)
   renders — deliberately a quiet inline bar, not a modal, since it's a
   one-line heads-up rather than something that needs to interrupt. */
.credit-confirm-bar {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  border: 1px solid var(--glass-border);
  background: rgba(255,255,255,0.55);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--text-light-secondary);
}
.credit-confirm-bar.visible { display: flex; }
.credit-confirm-actions { display: flex; gap: 8px; flex-shrink: 0; }
.credit-confirm-actions .secondary-btn,
.credit-confirm-actions .generate {
  padding: 7px 14px;
  font-size: 12px;
  width: auto;
}

/* auth + account pages */
section.block.glass-shell input[type="email"],
section.block.glass-shell input[type="password"] {
  width: 100%;
  margin-bottom: 10px;
  padding: 12px 14px;
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  font-size: 13.5px;
  background: rgba(255,255,255,0.55);
  color: var(--text-light);
}
section.block.glass-shell input::placeholder { color: var(--text-light-muted); }

.plans {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  padding: 4px;
}
.plan-card {
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-md);
  padding: 16px;
  background: rgba(255,255,255,0.4);
  flex: 1 1 210px;
  max-width: 260px;
  min-width: 190px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}
/* Dashed treatment for the non-highlighted plans (everything except
   "Most Popular" / the current plan) — matches the dashed "Create new
   project" affordance style used on the Projects page, so an unselected
   option reads the same way in both places. */
.plan-card.dashed { border: 1.5px dashed rgba(26,26,26,0.25); }
.plan-card.current { border-color: var(--accent); background: var(--accent-soft); }
.plan-card h3 { margin: 0 0 4px; font-size: 14.5px; color: var(--text-light); }
.plan-card .price { font-size: 19px; font-weight: 600; margin: 6px 0; color: var(--text-light); }
.plan-card .credits { font-size: 12px; color: var(--text-light-secondary); margin-bottom: 14px; }
.plan-card button {
  width: 100%;
  padding: 10px;
  border-radius: 10px;
  border: 1px solid var(--glass-border);
  background: transparent;
  color: var(--text-light);
  font-weight: 600;
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  letter-spacing: 0.01em;
  margin-top: auto;
  transition: background .18s ease, border-color .18s ease;
}
.plan-card button:hover:not(:disabled) { background: rgba(255,255,255,0.6); border-color: rgba(26,26,26,0.25); }
.plan-card button:disabled { cursor: default; }
.plan-card.current button { background: var(--active-bg); color: var(--active-text); border-color: transparent; }
.plan-card button { transition: background .18s ease, border-color .18s ease, transform .18s ease, box-shadow .18s ease; }
.plan-card button:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 3px 10px rgba(0,0,0,0.14); }
.plan-card button:active:not(:disabled) { transform: translateY(0); box-shadow: 0 1px 4px rgba(0,0,0,0.10); }
.plan-card button.generate {
  background: var(--moss);
  color: #fff;
  border: none;
  padding: 12px;
}
.plan-card button.generate:hover:not(:disabled) { background: var(--moss-dark); }

@keyframes vero-spin { to { transform: rotate(360deg); } }
.spinner {
  display: inline-block;
  width: 15px;
  height: 15px;
  border: 2px solid rgba(255,255,255,0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: vero-spin 0.7s linear infinite;
  vertical-align: -3px;
  margin-right: 8px;
}
.res-row { padding: 2px 2px 0; }
.res-pills { display: flex; gap: 4px; }
.res-pill {
  font-size: 10.5px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: 8px;
  background: rgba(255,255,255,0.35);
  color: var(--text-light-muted);
  border: none;
  cursor: pointer;
  white-space: nowrap;
  letter-spacing: 0.01em;
}
/* Selected resolution is a solid fill. White on --accent is 7.81:1, so
   unlike the old neon pink this needs no tinted workaround. */
.res-pill.selected {
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-deep);
  font-weight: 700;
  padding: 4px 11px;
}
.res-pill.locked { opacity: 0.5; cursor: not-allowed; }

/* display:none can't be transitioned, so every modal that used it just
   snapped open with no animation. Switching to opacity+visibility lets
   this fade in properly — and since 27 modal instances across the whole
   site share this one class (signup, login, logout confirm, plan/credit
   modals, lightbox, contact), fixing it here gets all of them at once
   rather than patching each individually. */
.auth-modal-overlay {
  display: flex;
  opacity: 0;
  visibility: hidden;
  position: fixed;
  inset: 0;
  background: rgba(20,24,16,0.35);
  backdrop-filter: blur(4px);
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
  transition: opacity 0.22s ease, visibility 0s linear 0.22s;
}
.auth-modal-overlay.visible {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.22s ease;
}
/* The modal itself gets a subtle rise-and-settle rather than just
   appearing — small enough to feel considered, not enough to feel slow. */
.auth-modal-overlay .auth-modal {
  transform: translateY(10px) scale(0.97);
  transition: transform 0.22s ease;
}
.auth-modal-overlay.visible .auth-modal {
  transform: translateY(0) scale(1);
}
.auth-modal {
  background: rgba(255,255,255,0.85);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  padding: 22px;
  width: 100%;
  max-width: 360px;
  box-shadow: 0 12px 40px rgba(0,0,0,0.2);
}

/* Password field eye-toggle — same control in signup, login, and
   anywhere else a password field appears, so it always looks and
   behaves identically. */
.password-field-wrap { position: relative; }
.password-toggle {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-55%);
  background: none;
  border: none;
  padding: 4px;
  cursor: pointer;
  color: var(--text-light-secondary);
  font-size: 16px;
  line-height: 1;
  display: flex;
}
.password-toggle:hover { color: var(--text-light); }

/* Six-digit verification code entry — one box per digit, auto-advancing
   as you type, styled to match the rest of the auth modal's glass
   inputs rather than looking like a bolted-on widget. */
.code-input-row {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin: 4px 0 6px;
}
.code-digit {
  width: 42px;
  height: 52px;
  text-align: center;
  font-size: 22px;
  font-weight: 600;
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  background: rgba(255,255,255,0.55);
  color: var(--text-light);
  box-sizing: border-box;
}
.code-digit:focus {
  outline: none;
  border-color: var(--accent, #6c5ce7);
  background: rgba(255,255,255,0.8);
}
.code-digit.error {
  border-color: #e0554f;
  background: rgba(224,85,79,0.06);
}

/* Mobile/tablet handling for the auth modal.
   Two real problems this solves:
   1. iOS Safari force-zooms the whole page whenever a focused input has a
      font-size under 16px — which yanked the layout mid-signup. Bumping
      every field to 16px on touch-sized screens stops that entirely.
   2. Six 42px boxes + gaps needs ~292px, which overflows inside a padded
      modal on a 320px-wide phone (iPhone SE). They shrink and tighten
      their gaps instead of overflowing. */
@media (max-width: 560px) {
  .auth-modal {
    padding: 18px 16px;
    max-width: 100%;
  }
  .auth-modal input[type="email"],
  .auth-modal input[type="password"],
  .auth-modal input[type="text"],
  .auth-modal select {
    font-size: 16px !important;
  }
  .code-input-row { gap: 6px; }
  .code-digit {
    width: 100%;
    max-width: 48px;
    height: 56px;
    font-size: 20px;
  }
  /* Comfortable thumb target on the toggle rather than a 16px tap area. */
  .password-toggle { right: 10px; padding: 8px; font-size: 18px; }
}

/* Very narrow phones — let the boxes flex down rather than overflow. */
@media (max-width: 360px) {
  .code-input-row { gap: 4px; }
  .code-digit { max-width: 44px; height: 52px; font-size: 18px; }
}

/* Shared "I am a..." select — same look in the signup page and the
   inline auth modal, so the sign-up experience reads as one consistent
   form no matter where it's triggered from. */
.select-field {
  width: 100%;
  padding: 12px 40px 12px 14px;
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  font-size: 13.5px;
  background: rgba(255,255,255,0.55) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23888888" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>') no-repeat right 14px center / 16px 16px;
  color: var(--text-light);
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  box-sizing: border-box;
}
.select-field:invalid { color: var(--text-light-muted); }

/* Shared two-column name row */
.name-field-row { display: flex; gap: 10px; margin-bottom: 10px; }
.name-field-row input { width: 100%; box-sizing: border-box; }

/* Shared site footer — identical on every page */
.site-footer {
  position: relative;
  z-index: 1;
  padding: 32px 24px 28px;
  text-align: center;
}
.site-footer-logo { height: 16px; width: auto; opacity: 0.7; margin: 0 auto 10px; display: block; }
.site-footer-tagline { font-size: 12px; color: var(--text-light-muted); margin: 0 0 14px; }
.site-footer-links { display: flex; justify-content: center; gap: 18px; flex-wrap: wrap; font-size: 12px; }
.site-footer-links a { color: var(--text-light-muted); text-decoration: none; transition: color .15s ease; }
.site-footer-links a:hover { color: var(--text-light); }

/* Compact pill-style button — same visual language as the landing page's
   input buttons (border, radius, hover), but sized small for action rows. */
.pill-btn {
  background: rgba(255,255,255,0.5);
  border: 1.5px solid var(--glass-border);
  border-radius: 20px;
  padding: 8px 16px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-light-secondary);
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.pill-btn:hover { background: rgba(255,255,255,0.8); color: var(--text-light); border-color: rgba(26,26,26,0.25); }

/* Small circular prev/next arrow for stepping through projects */
.project-nav-arrow {
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,0.5); border: 1px solid var(--glass-border);
  color: var(--text-light-secondary); cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 16px;
  transition: background .15s ease;
}
.project-nav-arrow:hover:not(:disabled) { background: rgba(255,255,255,0.85); color: var(--text-light); }
.project-nav-arrow:disabled { opacity: 0.3; cursor: default; }

/* Three-column grid of rendered results inside a project */
.thumb-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.thumb-grid .render-tile { border-radius: var(--radius-md); overflow: hidden; border: 1px solid var(--glass-border); background: rgba(255,255,255,0.4); cursor: pointer; display: flex; flex-direction: column; }
.thumb-grid .render-tile img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.thumb-grid .render-tile .render-tile-caption { padding: 8px 10px; font-size: 11px; color: var(--text-light-secondary); }
.render-tile-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 10px 8px; margin-top: auto; }
.render-tile-actions .reuse-link {
  /* var(--accent-deep), not --moss-dark: this selector is 0-2-0 and was
     outranking the generic `.reuse-link` accent rule (0-1-0) further
     down, so the accent never applied here. */
  font-size: 10.5px; font-weight: 600; color: var(--accent-deep); background: none; border: none;
  padding: 0; cursor: pointer; display: flex; align-items: center; gap: 4px; text-decoration: none;
}
.render-tile-actions .reuse-link:hover { text-decoration: underline; color: var(--accent); }
.render-tile-actions .reuse-link i { font-size: 12px; }
@media (max-width: 860px) { .thumb-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 640px) { .thumb-grid { grid-template-columns: repeat(2, 1fr); } }

/* Animated loading state for the Preview frame — same palette as the page
   backdrop, but shifting/flowing to signal active work happening. */
.output-loading {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: linear-gradient(
    120deg,
    #daeaf9, #d9f2d9, #fcf2d1, #fbe0e9, #daeaf9
  );
  background-size: 300% 300%;
  animation: outputLoadingFlow 6s ease-in-out infinite;
}
.output-loading.active { display: flex; }
.output-loading::before {
  content: "";
  position: absolute;
  inset: 0;
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);
}
.output-loading span {
  position: relative;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text-light-secondary);
  background: rgba(255,255,255,0.6);
  padding: 8px 18px;
  border-radius: 20px;
}
@keyframes outputLoadingFlow {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* Shared image lightbox — click any rendered result to view it large */
.lightbox-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(20,24,16,0.55);
  backdrop-filter: blur(6px);
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 24px;
}
.lightbox-overlay.visible { display: flex; }
.lightbox-content {
  max-width: min(900px, 92vw);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.lightbox-content img { max-width: 100%; max-height: 72vh; border-radius: var(--radius-md); box-shadow: 0 20px 60px rgba(0,0,0,0.3); display: block; }
/* NOTE: this rule was previously duplicated, and the first copy had
   "display: flex," with a comma — invalid CSS, so that declaration was
   silently dropped. Consolidated into one correct rule, now centred. */
.lightbox-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

.billing-toggle-pill {
  border: none;
  background: none;
  padding: 6px 14px;
  border-radius: 16px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-light-secondary);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.billing-toggle-pill.active { background: #1a1a1a; color: #fff; }
/* Currency toggle uses a grey active state instead of black, so it reads
   as a distinct control from the Monthly/Annually toggle next to it. */
.billing-toggle-pill.active-grey { background: #8a8a8a; color: #fff; }

/* Draggable input/output comparison slider — shared by the landing page's
   example gallery and the render page's Preview panel. */
.ba-slider {
  position: relative; width: 100%; max-width: 900px; margin: 0 auto; overflow: hidden;
  border-radius: var(--radius-lg); border: 1px solid var(--glass-border);
  cursor: ew-resize; -webkit-user-select: none; user-select: none; touch-action: pan-y;
  background: rgba(0,0,0,0.04);
}
.ba-slider img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  position: absolute; top: 0; left: 0; pointer-events: none; -webkit-user-drag: none;
}
.ba-slider .ba-base { position: relative; }
.ba-slider .ba-base img { position: static; }
.ba-slider .ba-output-wrap {
  position: absolute; inset: 0; overflow: hidden;
  clip-path: inset(0 0 0 50%); -webkit-clip-path: inset(0 0 0 50%);
}
.ba-handle {
  position: absolute; top: 0; bottom: 0; left: 50%; width: 0;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.ba-handle::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 2px;
  margin-left: -1px;
  background: #fff; box-shadow: 0 0 0 1px rgba(0,0,0,0.18), 0 0 8px rgba(0,0,0,0.25);
}
/* The grip is a real element (not a ::after pseudo-element) so it can hold
   a crisp inline SVG icon instead of a Unicode glyph, whose rendering
   varies by font/OS. It's added after the line in paint order, so it sits
   visually on top of the divider — matching the reference look of the
   circle fully covering the line. */
.ba-handle-grip {
  position: relative; z-index: 1;
  width: 34px; height: 34px; flex-shrink: 0;
  border-radius: 50%; background: #fff; color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}
.ba-handle-grip svg { width: 16px; height: 16px; display: block; }
.ba-label {
  position: absolute; top: 10px; padding: 3px 10px; font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em; border-radius: 20px;
  /* Deliberately NOT the tinted treatment used everywhere else: these
     labels sit on top of photographs, and a 10% wash over an arbitrary
     image is invisible. They need an opaque fill to stay legible against
     bright sky or pale paving. */
  background: var(--accent); color: #fff; pointer-events: none; z-index: 2;
}
.ba-label-input { left: 10px; }
.ba-label-output { right: 10px; }

/* Preview eye icon — bottom-right of the Render side, same dark-pill
   treatment as the INPUT/RENDER labels above for visual consistency, but
   actually clickable (labels are pointer-events:none; this needs the
   opposite) since it's what opens the full-size lightbox now, not a
   click anywhere on the image. */
.ba-eye-btn {
  position: absolute;
  bottom: 10px;
  right: 10px;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.55);
  color: #fff;
  cursor: pointer;
  transition: background 0.15s ease;
}
.ba-eye-btn:hover { background: rgba(0,0,0,0.75); }
/* SVG sizes itself via its width/height attrs; this just guarantees it
   sits centred and inherits the button's white regardless of any
   inherited text styling. */
.ba-eye-btn svg { display: block; color: #fff; }

/* Render page's Preview panel needs the slider to fill the output frame
   (which has its own fixed sizing/aspect handling), not center at a fixed
   max-width like the landing page's examples. */
.output-frame .ba-slider { max-width: none; width: 100%; height: 100%; border: none; border-radius: 0; }
/* Both layers pinned to the slider box so they stack exactly. */
.output-frame .ba-slider .ba-base {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.output-frame .ba-slider .ba-base img {
  width: 100%;
  height: 100%;
}

/* The shared .ba-slider img rule uses object-fit: cover, which crops
   whenever the container's aspect ratio (dictated here by flexible layout
   space, not by the image) doesn't match the image's own ratio. That's
   fine for the curated, ratio-matched landing-page examples, but a real
   uploaded reference + AI-generated result can easily differ — so the
   render page's preview always shows the complete image instead, same as
   the plain (non-slider) image it replaced. */
.output-frame .ba-slider img { object-fit: contain; background: rgba(0,0,0,0.03); }

/* Credit badge — now a plain link straight to /account.html#plan-section,
   no popover. .credit-badge-wrap kept for layout (badge + "Get more"
   pill sit together). */
/* No gap by default — when credits run low the badge gets .attached
   (square inner corners, no right border) so it and the "Get more" pill
   read as ONE control. A gap here broke that seam. */
/* Structured identically to .studio-switch so the two pills opposite each
   other are the same object with different contents: one bordered,
   rounded, overflow-hidden container; segments inside carry no border or
   radius of their own. Only the colour differs. */
.credit-badge-wrap {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  overflow: hidden;
  flex-shrink: 0;
}

/* Unverified-account notice — used on account.html's plan section (and
   reusable anywhere else it's needed) rather than a floating popover. */
.unverified-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  background: rgba(168,83,47,0.08);
  border: 1px solid rgba(168,83,47,0.2);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 12.5px;
}
.unverified-row span { color: var(--clay); font-weight: 600; }

/* Wider modal variant for the upgrade/purchase flow — needs room for a
   3-column plan grid, unlike the narrow auth modal it's based on. */
.auth-modal.plan-modal { max-width: 700px; }
.plan-modal-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin: 16px 0; }
.plan-modal-grid .plan-card.recommended { border-color: var(--moss); background: rgba(26,26,26,0.05); }
.plan-modal-packs { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin-top: 10px; }

/* Scroll-reveal: sections fade + rise into place as they enter view,
   rather than the whole landing page just being there instantly. Kept
   deliberately subtle (12px of movement, 0.5s) — this should read as
   quality, not as a flashy animation demo. Respects reduced-motion. */
.scroll-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.scroll-reveal.revealed {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .scroll-reveal { opacity: 1; transform: none; transition: none; }
}


/* ---------------------------------------------------------------
   Hover states for interactive elements that had none.
   Anything clickable should acknowledge the cursor — without it,
   thumbnails and pills read as static images rather than controls.
   All use transforms/shadows rather than layout-affecting properties
   so nothing reflows on hover, and all are disabled under
   prefers-reduced-motion.
   --------------------------------------------------------------- */

/* Render-history thumbnails (Account + Projects). These are clickable
   (cursor:pointer was already set) but gave no feedback at all. */
.thumb-grid .render-tile {
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.thumb-grid .render-tile:hover {
  transform: translateY(-2px);
  border-color: rgba(26,26,26,0.25);
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
}
/* Subtle zoom on the image itself, clipped by the tile's overflow:hidden
   — reads as "there's more to see here" without moving the tile's box. */
.thumb-grid .render-tile img { transition: transform 0.25s ease; }
.thumb-grid .render-tile:hover img { transform: scale(1.04); }

/* Resolution pills (1K / 2K) on the render page. */
.res-pill { transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
.res-pill:hover:not(.selected) {
  background: rgba(255,255,255,0.75);
  border-color: rgba(26,26,26,0.2);
  color: var(--text-light);
}

/* Verification code boxes — hovering should show they're editable. */
.code-digit { transition: border-color 0.15s ease, background 0.15s ease; }
.code-digit:hover:not(:focus) {
  border-color: rgba(26,26,26,0.25);
  background: rgba(255,255,255,0.7);
}

/* Monthly/Annual billing toggle. */
.billing-toggle-pill { transition: background 0.15s ease, color 0.15s ease; }
.billing-toggle-pill:hover:not(.active-grey) {
  background: rgba(255,255,255,0.7);
  color: var(--text-light);
}

/* Search field on Projects — indicate the whole row is focusable. */
.projects-search-row { transition: border-color 0.15s ease, background 0.15s ease; }
.projects-search-row:hover { border-color: rgba(26,26,26,0.2); }

/* The before/after drag handle — it's draggable but looked inert. */
.ba-handle-grip { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.ba-slider:hover .ba-handle-grip {
  transform: scale(1.08);
  box-shadow: 0 3px 12px rgba(0,0,0,0.28);
}

@media (prefers-reduced-motion: reduce) {
  .thumb-grid .render-tile,
  .thumb-grid .render-tile img,
  .res-pill,
  .code-digit,
  .billing-toggle-pill,
  .projects-search-row,
  .ba-handle-grip { transition: none; }
  .thumb-grid .render-tile:hover,
  .thumb-grid .render-tile:hover img,
  .ba-slider:hover .ba-handle-grip { transform: none; }
}


/* ---------------------------------------------------------------
   (j) Signup consent. Shown only in signup mode — logging in isn't a
   fresh agreement, so re-asking there would be noise. The checkbox is
   `required`, so the browser blocks submission and focuses it natively
   rather than us hand-rolling an error state.
   --------------------------------------------------------------- */
.terms-consent {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 2px 0 14px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-light-secondary);
  text-align: left;
}
.terms-consent input[type="checkbox"] {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin: 1px 0 0;
  accent-color: #1a1a1a;
  cursor: pointer;
}
.terms-consent label { cursor: pointer; }
.terms-consent a {
  color: var(--text-light);
  text-decoration: underline;
  font-weight: 600;
}
.terms-consent a:hover { color: #000; }

/* ---------------------------------------------------------------
   Feedback widget. Fixed bottom-right on the landing and app pages
   only — not account/admin, where it'd compete with real controls.
   Visual language matches the "Beta" pill + black button pattern.
   --------------------------------------------------------------- */
.feedback-widget {
  position: fixed;
  right: 20px;
  bottom: 20px;
  /* Deliberately below every modal overlay (.auth-modal-overlay: 100,
     .lightbox-overlay: 200) so opening any modal covers this — both
     visually (caught under the overlay's own blur, same as the rest of
     the page) and functionally (the overlay's full-viewport backdrop
     intercepts clicks before they reach a widget stacked beneath it). */
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 8px;
}
.feedback-beta-badge {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-light-secondary);
  background: rgba(255,255,255,0.75);
  border: 1px solid var(--glass-border);
  padding: 5px 11px;
  border-radius: 999px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.feedback-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* Solid accent. A persistent floating control reads better filled
     than outlined, and white on --accent clears AA comfortably. */
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-deep);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: 999px;
  cursor: pointer;
  letter-spacing: 0.01em;
  box-shadow: 0 2px 8px rgba(0,0,0,0.14);
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease;
}
.feedback-trigger:hover {
  background: var(--accent-softer);
  border-color: var(--accent);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(58,86,98,0.30);
}
.feedback-trigger:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(0,0,0,0.18); }
.feedback-trigger:focus-visible { outline: 2px solid rgba(26,26,26,0.55); outline-offset: 2px; }

@media (max-width: 560px) {
  .feedback-widget { right: 14px; bottom: 14px; }
  .feedback-beta-badge { display: none; }
}

.feedback-textarea {
  width: 100%;
  min-height: 110px;
  resize: vertical;
  padding: 12px 14px;
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.5;
  background: rgba(255,255,255,0.55);
  color: var(--text-light);
  box-sizing: border-box;
  margin-bottom: 10px;
}
.feedback-textarea:focus { outline: none; border-color: rgba(26,26,26,0.35); }
.feedback-anon-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 16px;
  font-size: 12.5px;
  color: var(--text-light-secondary);
}
.feedback-anon-row input[type="checkbox"] {
  flex-shrink: 0;
  width: 15px;
  height: 15px;
  margin: 1px 0 0;
  accent-color: #1a1a1a;
  cursor: pointer;
}
.feedback-anon-row label { cursor: pointer; }

/* (A) About-page subtitles. All four — the page label and the three
   subsection headers — share one style so they read as one consistent
   voice, rather than the page label being a tiny 11px utility tag while
   the subsections underneath were an unrelated 15px. */
.about-subtitle {
  font-size: 14.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text-light);
  margin: 0 2px 6px;
}

/* (B) First/last name fields on the account page. Previously all their
   styling was inline, which — being higher specificity than any
   stylesheet selector — meant a :hover rule here couldn't visibly change
   anything about them without !important. Moved the styling into this
   class instead, so hover and focus behave like every other input. */
.profile-name-input {
  padding: 12px 14px;
  border: 1px solid var(--glass-border);
  border-radius: 14px;
  font-family: inherit;
  font-size: 13.5px;
  background: rgba(255,255,255,0.55);
  color: var(--text-light);
  transition: background .15s ease, border-color .15s ease;
}
.profile-name-input:hover:not(:focus) { background: rgba(255,255,255,0.72); border-color: rgba(26,26,26,0.22); }
.profile-name-input:focus { outline: none; background: rgba(255,255,255,0.85); border-color: rgba(26,26,26,0.35); }
.profile-name-input::placeholder { color: var(--text-light-muted); }

/* ---------------------------------------------------------------
   (E) Maple leaf mark. Fixed bottom-left, mirroring the feedback
   widget's bottom-right position. Black by default; on hover/focus it
   turns red and a small speech-bubble note pops up above it. No auth
   gating — this one isn't an action, just a mark.
   --------------------------------------------------------------- */
.leaf-widget {
  position: fixed;
  left: 20px;
  bottom: 20px;
  /* Same reasoning as .feedback-widget above — stays under every modal
     overlay rather than floating sharp on top of a blurred backdrop. */
  z-index: 60;
}
.leaf-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255,255,255,0.75);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  transition: transform .18s ease, box-shadow .18s ease;
}
.leaf-icon-btn svg path { transition: fill .25s ease; }
.leaf-icon-btn:hover,
.leaf-icon-btn:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0,0,0,0.14);
}
.leaf-icon-btn:hover svg path,
.leaf-icon-btn:focus-visible svg path { fill: #c0392b; }
.leaf-icon-btn:focus-visible { outline: 2px solid rgba(26,26,26,0.55); outline-offset: 2px; }

/* (C) Slides out to the right of the leaf rather than popping up as a
   speech bubble above it — reads more like a label reveal than an alert,
   and staying to the right (toward the page center) avoids clipping
   against the left edge of the screen where this widget lives. */
.leaf-tooltip {
  position: absolute;
  top: 50%;
  left: calc(100% + 10px);
  background: #1a1a1a;
  color: #fff;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  padding: 8px 13px;
  border-radius: 10px;
  opacity: 0;
  transform: translateY(-50%) translateX(-8px);
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
}
.leaf-icon-btn:hover ~ .leaf-tooltip,
.leaf-icon-btn:focus-visible ~ .leaf-tooltip {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}

@media (max-width: 560px) {
  .leaf-widget { left: 14px; bottom: 14px; }
}

/* ---------------------------------------------------------------
   Admin dashboard. Only ever rendered for ADMIN_EMAIL, so this is
   dense-information styling rather than the softer marketing look
   used elsewhere in the app.
   --------------------------------------------------------------- */
.admin-section-title {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text-light);
  margin: 0 2px 12px;
}
.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
}
.admin-stat {
  background: rgba(255,255,255,0.5);
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 14px 16px;
}
.admin-stat-label {
  margin: 0 0 4px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-light-secondary);
}
.admin-stat-value { margin: 0; font-size: 24px; font-weight: 700; line-height: 1.2; }
.admin-stat-sub { margin: 3px 0 0; font-size: 11px; color: var(--text-light-muted); }
.admin-stat.highlight { background: var(--accent-softer); border-color: var(--accent-line); }

.admin-table-wrap { overflow-x: auto; margin-top: 4px; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.admin-table th {
  text-align: left;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-light-secondary);
  font-weight: 600;
  padding: 8px 10px;
  border-bottom: 1px solid var(--glass-border);
  white-space: nowrap;
}
.admin-table td {
  padding: 10px;
  border-bottom: 1px solid rgba(26,26,26,0.06);
  vertical-align: middle;
}
.admin-table tbody tr:hover { background: rgba(255,255,255,0.45); }
.tier-badge {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.tier-badge.free { background: rgba(26,26,26,0.07); color: var(--text-light-secondary); }
.tier-badge.paid { background: #1a1a1a; color: #fff; }
.tier-badge.cancelling { background: rgba(192,57,43,0.12); color: #c0392b; }

/* Time-window figures: one row, each quantity in its own light outline.
   Scrolls horizontally on narrow screens rather than wrapping, so the
   series stays readable as a single comparable run. */
.admin-window-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 2px;
}
.admin-window-cell {
  flex: 1 1 0;
  min-width: 88px;
  background: rgba(255,255,255,0.5);
  border: 1px solid rgba(26,26,26,0.16);
  border-radius: 10px;
  padding: 11px 12px;
  text-align: center;
}
.admin-window-cell.highlight {
  background: var(--accent-softer);
  border-color: var(--accent-line);
}
.admin-window-label {
  margin: 0 0 4px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-light-secondary);
  white-space: nowrap;
}
.admin-window-value { margin: 0; font-size: 20px; font-weight: 700; line-height: 1.15; }

/* Internal-account status badges. */
.tier-badge.admin { background: var(--accent-soft); border: 1px solid var(--accent-line); color: var(--accent-deep); }
.tier-badge.tester { background: #2e7d4f; color: #fff; }

/* The Annually toggle carries a light outline and a hot pink dot so the
   cheaper option is visibly flagged even before the savings badge
   appears on the cards below. Border only shows when INACTIVE — once
   selected the black fill is the signal, and an outline on top of it
   would just look like a rendering artefact. */
.billing-toggle-pill.has-savings-dot {
  position: relative;
  border: 1px solid rgba(26,26,26,0.22);
  overflow: visible;
}
.billing-toggle-pill.has-savings-dot.active { border-color: transparent; }
.billing-toggle-pill.has-savings-dot::after {
  content: "";
  position: absolute;
  top: -4px;
  right: -4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  /* Ring in the panel background so the dot reads as sitting on top of
     the pill rather than merging into its edge. */
  box-shadow: 0 0 0 2px rgba(255,255,255,0.9);
}

/* Admin-only footer link, hot pink so it's clearly distinct from the
   normal footer links. Only ever visible to ADMIN_EMAIL — see
   revealAdminOnlyLinks in safe-fetch.js. */
.site-footer-links a[data-admin-only] {
  color: var(--accent-deep);
  font-weight: 700;
}
.site-footer-links a[data-admin-only]:hover { color: var(--accent); }

/* =================================================================
   MOBILE HARDENING
   ================================================================= */

/* --- Tall modals must be able to scroll -------------------------
   The signup modal is the tallest in the app (label, subtext, email,
   password, first name, last name, user-type select, terms consent,
   submit, forgot-password, and the login toggle). On a small phone
   that exceeds the viewport, and with no scrolling the Sign Up button
   sat below the fold with no way to reach it — signup was simply
   impossible on an iPhone SE. dvh rather than vh so the collapsing
   mobile browser chrome doesn't cut the modal off; vh first as a
   fallback for browsers without dvh. */
.auth-modal-overlay {
  overflow-y: auto;
  overscroll-behavior: contain;
}
.auth-modal {
  max-height: calc(100vh - 40px);
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Keeps the scrollbar off the rounded corners. */
  -webkit-overflow-scrolling: touch;
}

/* --- Fixed corner widgets ---------------------------------------
   The feedback and leaf widgets are position:fixed at the bottom, so
   they float above whatever the page ends with — on mobile that's the
   footer, and they were covering the footer links (Privacy Policy,
   Back to Top, and the admin link) so those couldn't be tapped at all.
   Reserve clearance at the end of the page equal to the widget height
   plus a margin. Only applied where the widgets actually exist. */
body:has(.feedback-widget) .site-footer,
body:has(.leaf-widget) .site-footer {
  padding-bottom: 88px;
}
/* :has() is unsupported on older Safari/Firefox; this is the safety net
   for the pages that carry the widgets, applied unconditionally at
   mobile widths where the collision actually happens. */
@media (max-width: 560px) {
  .site-footer { padding-bottom: 88px; }
}

/* Respect the iPhone home-indicator area and any rounded-corner insets,
   so the widgets don't sit under the gesture bar or get clipped. */
.feedback-widget {
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  right: calc(20px + env(safe-area-inset-right, 0px));
}
.leaf-widget {
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  left: calc(20px + env(safe-area-inset-left, 0px));
}
@media (max-width: 560px) {
  .feedback-widget {
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    right: calc(14px + env(safe-area-inset-right, 0px));
  }
  .leaf-widget {
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    left: calc(14px + env(safe-area-inset-left, 0px));
  }
  /* The tooltip slides out to the RIGHT of the leaf. At 320-360px that
     runs it under (or past) the feedback button on the other side, so
     on mobile it opens upward instead, where there's nothing to hit. */
  .leaf-tooltip {
    left: 0;
    top: auto;
    bottom: calc(100% + 10px);
    transform: translateY(6px);
    max-width: calc(100vw - 40px);
    white-space: normal;
  }
  .leaf-icon-btn:hover ~ .leaf-tooltip,
  .leaf-icon-btn:focus-visible ~ .leaf-tooltip {
    transform: translateY(0);
  }
}

/* --- Admin dashboard on a phone ---------------------------------
   Six outlined cells at 88px each overflow a 360px screen. Narrower
   cells fit four across, and the row still scrolls for the longer
   groups rather than squashing numbers illegibly. */
@media (max-width: 560px) {
  .admin-window-cell { min-width: 74px; padding: 9px 8px; }
  .admin-window-label { font-size: 9px; letter-spacing: 0.03em; }
  .admin-window-value { font-size: 17px; }
  .admin-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
  .admin-stat-value { font-size: 20px; }
  /* Nine columns will never fit a phone; make the horizontal scroll
     obvious rather than letting the table look truncated. */
  .admin-table-wrap {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .admin-table th, .admin-table td { padding: 8px; white-space: nowrap; }
}

/* --- Account page name fields -----------------------------------
   Two inputs side by side leave ~140px each on a small phone, which
   truncates the placeholders. Stack them below 400px. */
@media (max-width: 400px) {
  .profile-name-row { flex-direction: column; }
  /* flex:1 is set inline on these; in a column that becomes vertical
     grow, stretching the inputs. Reset it. */
  .profile-name-input { width: 100%; flex: none; }
}

/* iOS zooms the page in when a focused input is under 16px. The auth
   modal already guards this; these are the fields outside it. */
@media (max-width: 560px) {
  .profile-name-input,
  .feedback-textarea,
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  textarea,
  select {
    font-size: 16px;
  }
}

/* =================================================================
   MOBILE FIXES FROM DEVICE TESTING (iPhone, Safari)
   ================================================================= */

/* --- Landing nav: logo was overlapping the HOME tab --------------
   .lp-nav is a non-wrapping space-between row, and at mobile widths
   .nav-tabs takes `flex: 1 1 100%` and scrolls horizontally. Inside a
   nowrap parent that made the tab strip demand the full width and ride
   over the logo. The other pages' <header> already drops its nav to a
   second row at 820px; the landing nav never got the same treatment. */
@media (max-width: 820px) {
  .lp-nav {
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 20px;
  }
  #lpNavRight {
    width: 100%;
    /* min-width:0 lets the scrolling tab strip actually shrink instead
       of forcing the row wider than the screen. */
    min-width: 0;
  }
  .lp-nav .nav-tabs { min-width: 0; }
}

/* --- Feedback button was covering page content ------------------
   It's fixed to the bottom-right, and on a phone the full "Send
   Feedback" pill is wide enough to sit on top of headings, input
   options, and buttons mid-page — not just the footer. On mobile it
   collapses to a compact circular icon button, matching the leaf on
   the other side, so it stays reachable without blocking content. */
.feedback-trigger i { font-size: 15px; line-height: 1; display: none; }
@media (max-width: 700px) {
  .feedback-trigger {
    width: 42px;
    height: 42px;
    padding: 0;
    border-radius: 50%;
    justify-content: center;
    gap: 0;
  }
  .feedback-trigger i { display: block; font-size: 18px; }
  .feedback-trigger-label { display: none; }
  /* The Beta badge is already hidden at 560px; hide it here too so the
     icon doesn't sit next to an orphaned pill between 560 and 700. */
  .feedback-beta-badge { display: none; }
}

/* --- Landing example frame: large empty gap on mobile -----------
   min-height: 420px is right for a desktop-width landscape example,
   but on a phone the image is only ~200px tall, leaving a big blank
   area beneath it (visible as dead white space under the before/after
   slider). Let the image set the height instead. */
@media (max-width: 860px) {
  .lp-input-frame { min-height: 260px; }
}
@media (max-width: 560px) {
  .lp-input-frame { min-height: 0; }
  .lp-input-frame img { height: auto; }
}

/* --- Studio row: section tabs + credits ---------------------------
   Sits below the site nav, aligned to the same edges as the panels
   underneath so the whole page reads on one grid. */
.studio-row {
  width: 100%;
  max-width: 1180px;
  /* Tight to the panels below — the row is a header for them, not a
     separate band. The panels drop their own top padding to match.
     The top margin separates it from the header hairline, which
     otherwise sat directly against the tab pill. */
  margin: 22px auto 10px;
  padding: 0 24px;
  box-sizing: border-box;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

/* A segmented pill, matching the credits pill opposite it: one rounded
   container, hairline divisions, selected segment filled black. This
   replaced a row of underlined text tabs — as a pill it reads as a
   control you operate rather than a second site menu, and it balances
   the credits pill on the other end of the row. */
.studio-switch {
  display: inline-flex;
  align-items: stretch;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: 20px;
  /* 3px of padding turns this into a track that the active segment sits
     INSIDE as its own rounded pill. Previously the active segment drew a
     rectangular inset ring flush against a rounded, overflow-hidden
     container — so its edge collided with the corner radius and showed
     as a hard sliver. Insetting it removes the collision entirely. */
  padding: 3px;
  flex-shrink: 0;
}
.studio-tab {
  background: none;
  border: none;
  /* No dividing hairlines: they fight with a rounded active segment,
     and the fill alone is enough to show which one is selected. */
  border-radius: 17px;
  color: var(--text-light-secondary);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 8px 16px;
  cursor: pointer;
  white-space: nowrap;
  transition: background .18s ease, color .18s ease;
}
.studio-tab:hover:not(.active) {
  background: rgba(255,255,255,0.95);
  color: var(--text-light);
}
.studio-tab:focus-visible { outline: 2px solid rgba(26,26,26,0.55); outline-offset: -2px; }
.studio-tab.active {
  background: #1a1a1a;
  color: #fff;
}

main.workspace-view {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  box-sizing: border-box;
  /* One padding declaration, not two — this rule previously set
     `padding-top: 6px` and then a `padding: 36px 24px 48px` shorthand
     further down in the SAME rule, which silently overwrote the top
     value back to 36px (a later property always wins within one rule,
     regardless of which looks more specific). That's why Projects and
     Render History sat much further from the tab bar than Render,
     which lives in a separate rule with no such conflict. */
  padding: 6px 24px 48px;
  position: relative;
  z-index: 1;
}

@media (max-width: 560px) {
  .studio-row { padding: 0 16px; margin-top: 16px; margin-bottom: 16px; gap: 10px; }
  .studio-tab { padding: 8px 11px; font-size: 11.5px; }
  main.workspace-view { padding: 28px 16px 32px; }
}

/* --- Pricing page ------------------------------------------------
   Cards sit on the page rather than inside a glass shell so each tier
   reads as its own object, and side by side so tiers can be compared at
   a glance (the account page's .plans is single-column because it lives
   in a narrow sidebar there). Kept in the app's light palette rather
   than the dark reference — consistency with the rest of the site
   matters more than matching a precedent's colour scheme. */
.pricing-plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  align-items: stretch;
  max-width: 1000px;
  margin: 0 auto;
}
.pricing-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  padding: 24px 22px;
}
/* The recommended tier gets a black border and a lift rather than a
   different fill, so it stands out without introducing a second colour. */
.pricing-card.featured {
  border-color: #1a1a1a;
  border-width: 2px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.10);
}
.pricing-flag {
  position: absolute;
  top: -11px;
  left: 50%;
  transform: translateX(-50%);
  background: #1a1a1a;
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 12px;
  border-radius: 999px;
  white-space: nowrap;
}
.pricing-name { font-size: 19px; font-weight: 700; margin: 0 0 4px; }
.pricing-desc { font-size: 12.5px; color: var(--text-light-secondary); margin: 0 0 16px; line-height: 1.5; min-height: 34px; }
.pricing-price { font-size: 30px; font-weight: 700; margin: 0; line-height: 1.1; }
.pricing-sub { font-size: 12px; color: var(--text-light-secondary); margin: 5px 0 0; }
.pricing-save {
  display: inline-block;
  margin-top: 10px;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-deep);
  font-size: 12px;
  font-weight: 700;
  padding: 5px 13px;
  border-radius: 999px;
}
.pricing-credits {
  background: rgba(26,26,26,0.05);
  border: 1px solid rgba(26,26,26,0.08);
  border-radius: 12px;
  padding: 13px 15px;
  margin: 16px 0;
}
/* Number and its unit tag on one baseline. The tag used to float right,
   which pushed it to the far edge of the box and made the pair read as
   two unrelated items. */
.pricing-credits-row { display: flex; align-items: baseline; gap: 9px; }
.pricing-credits strong { font-size: 21px; font-weight: 700; }
.pricing-credits-tag {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-light-secondary);
  background: rgba(255,255,255,0.7);
  border-radius: 999px;
  padding: 3px 9px;
}
.pricing-credits p { font-size: 11.5px; color: var(--text-light-secondary); margin: 6px 0 0; }
/* Matches the weight of the app's other primary buttons (Download My
   Data, Render) rather than being a thinner variant. */
.pricing-card .generate {
  margin-top: auto;
  width: 100%;
  padding: 14px 24px;
  font-size: 13.5px;
}

@media (max-width: 560px) {
  .pricing-plans { grid-template-columns: 1fr; }
  .pricing-desc { min-height: 0; }
}

/* --- Project cards (shared) --------------------------------------
   These lived inline in projects.html, which is why the Studio's
   Projects tab rendered unstyled — app.html loads style.css but never
   saw them. Moved here so both surfaces render identically and can't
   drift apart. */
.projects-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; }
.project-card {
  display: block; text-align: left; background: rgba(255,255,255,0.5);
  border: 1px solid var(--glass-border); border-radius: var(--radius-md);
  overflow: hidden; cursor: pointer; text-decoration: none; color: inherit;
  transition: background .18s ease, transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.project-card:hover {
  background: rgba(255,255,255,0.8);
  transform: translateY(-2px);
  border-color: rgba(26,26,26,0.22);
  box-shadow: 0 6px 18px rgba(0,0,0,0.12);
}
.project-cover {
  width: 100%; aspect-ratio: 4/3; background: rgba(255,255,255,0.4);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-light-muted); overflow: hidden;
}
.project-cover img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.project-card:hover .project-cover img { transform: scale(1.04); }
.project-card-body { padding: 12px; }
.project-card-body strong { display: block; font-size: 13.5px; margin-bottom: 2px; }
.project-card-body span { font-size: 11.5px; color: var(--text-light-secondary); }
.new-project-card {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  height: 100%; min-height: 180px;
  border: 1.5px dashed rgba(26,26,26,0.25); border-radius: var(--radius-md);
  background: none; color: var(--text-light-secondary); cursor: pointer; font: inherit; font-size: 12.5px;
  transition: background .18s ease, border-color .18s ease, color .18s ease;
}
.new-project-card:hover {
  background: rgba(255,255,255,0.45);
  border-color: rgba(26,26,26,0.45);
  color: var(--text-light);
}
.new-project-card svg { display: block; }

/* --- Sticky footer -----------------------------------------------
   The Projects and Render History tabs are often short — a couple of
   thumbnails — which left the footer floating in the middle of the
   viewport. Flexing the body and letting the footer take the leftover
   space pins it to the bottom whenever the content is shorter than the
   screen, without forcing a scrollbar when it isn't. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}
.site-footer { margin-top: auto; }

/* --- Account icon (top right, beside Login/Logout) ----------------
   Account stopped being a tab so the centre row is the same three
   destinations in both signed-in and signed-out states. As an icon it
   groups with Logout as "you", rather than sitting among the places you
   can go. Sized to match .nav-tab's height so the right-hand group
   lines up. */
.nav-account-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  color: var(--text-light);
  text-decoration: none;
  flex-shrink: 0;
  transition: background .18s ease, border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.nav-account-icon:hover {
  background: rgba(255,255,255,0.95);
  border-color: rgba(26,26,26,0.22);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0,0,0,0.10);
}
.nav-account-icon:active { transform: translateY(0); box-shadow: 0 1px 4px rgba(0,0,0,0.10); }
.nav-account-icon:focus-visible { outline: 2px solid rgba(26,26,26,0.55); outline-offset: 2px; }
.nav-account-icon svg { display: block; }
@media (max-width: 560px) {
  .nav-account-icon { width: 34px; height: 34px; }
  .nav-account-icon svg { width: 16px; height: 16px; }
}

/* --- Founding-member discounted pricing ---------------------------
   New price above, original struck through beneath it — the order the
   markup sketch showed, and the order that reads correctly: the number
   you'll actually pay is the headline, the old one is context. */
.pricing-price-discounted { color: var(--accent-deep); }
.pricing-price-was {
  margin: 2px 0 0;
  font-size: 17px;
  font-weight: 600;
  color: var(--text-light-muted);
  /* Pink strike matching the sketch. text-decoration-color is separate
     from the text colour so the rule reads as an annotation over a muted
     number rather than the whole line turning pink. */
  text-decoration: line-through;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
}

/* --- Inputs still in refinement -----------------------------------
   Five modes are held back until their output is consistent enough to
   show a professional audience. Two different treatments on purpose:

   Studio (.mode-row-soon) — genuinely disabled. These can't be run, and
   the row is inert rather than looking clickable and failing.

   Landing page (.lp-input-label-soon) — still fully clickable. The
   before/after examples are marketing proof and were generated ahead of
   time, so there's nothing to gate; only a quiet marker so a visitor
   understands the distinction. */
.mode-row-soon {
  opacity: 0.5;
  cursor: not-allowed;
}
/* Cancel the interactive affordances the base .mode-row carries — a row
   that lifts under the cursor reads as clickable no matter how faded. */
.mode-row-soon:hover {
  background: none;
  transform: none;
  box-shadow: none;
}
.mode-soon-pill,
.lp-input-soon-pill {
  flex-shrink: 0;
  align-self: center;
  margin-left: 10px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-light-secondary);
  background: rgba(26,26,26,0.07);
  border: 1px solid rgba(26,26,26,0.10);
  padding: 3px 8px;
  border-radius: 999px;
}
.mode-row-soon .texts { opacity: 1; }

/* Landing page: muted, but deliberately NOT disabled-looking, because it
   still does something when clicked. */
.lp-input-label-soon {
  color: var(--text-light-muted);
}
.lp-input-label-soon::after {
  content: "In refinement";
  display: inline-block;
  margin-left: 8px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-light-secondary);
  background: rgba(26,26,26,0.07);
  border: 1px solid rgba(26,26,26,0.10);
  padding: 2px 7px;
  border-radius: 999px;
  vertical-align: 1px;
}

/* 4K sits on a preview model — marked so it doesn't read as an equal peer
   of 1K and 2K, which run on the stable model. */
.res-pill-preview::after {
  content: "Preview";
  margin-left: 6px;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-light-secondary);
  background: rgba(26,26,26,0.08);
  border-radius: 999px;
  padding: 2px 6px;
  vertical-align: 1px;
}
.res-pill-preview.selected::after {
  color: rgba(255,255,255,0.85);
  background: rgba(255,255,255,0.18);
}

/* Resolution tiers locked behind a paid plan. Shown rather than hidden so
   the upgrade path stays visible, but genuinely inert — the pill must not
   read as clickable while being disabled. */
.res-pill-locked {
  opacity: 0.45;
  cursor: not-allowed;
}
.res-pill-locked:hover {
  background: none;
  transform: none;
  box-shadow: none;
  border-color: var(--glass-border);
}

/* --- Accent system -------------------------------------------------
   One colour applied consistently to INTERACTIVE STATE — selection,
   hover, focus, links — rather than sprinkled as decoration. Primary
   CTAs (Try VSTLA Free, Subscribe, Save) stay black so the accent
   remains an accent and doesn't become a second primary. */

/* Focus, app-wide. Visible on every surface here, unlike the old dark ring. */
:focus-visible { outline-color: var(--accent); }

/* Studio section tabs. */
/* The active tab has a solid dark fill (see .studio-tab.active above), so
   it takes the accent as its BACKGROUND and keeps white text. Setting
   `color: var(--accent)` here previously left the label sitting on that
   dark fill in a mid-tone accent — near-invisible. */
/* Tinted pill, not a solid fill: soft accent wash, accent border, deep
   accent label. Deep-on-tint is 4.86:1 at worst (orange), so this clears
   AA for small text on every theme — the solid version could not. */
.studio-tab.active {
  background: var(--accent-soft);
  color: var(--accent-deep);
  box-shadow: inset 0 0 0 1px var(--accent-line);
}
.studio-tab:hover:not(.active) { border-bottom-color: var(--accent-line); color: var(--accent); }

/* Inline links and secondary actions. */
.legal-body a,
.about-body a,
.link-accent,
.reuse-link { color: var(--accent); }
.legal-body a:hover,
.about-body a:hover,
.link-accent:hover,
.reuse-link:hover { color: var(--accent-deep); }

/* Secondary buttons pick up the accent on hover rather than staying grey —
   this is most of the "used a tad more" surface area. */
.secondary-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Tags and badges: tinted fill, accent text. */
.mode-soon-pill,
.lp-input-label-soon::after,
.res-pill-preview::after,
.tier-badge.free {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent);
}
.res-pill-preview.selected::after {
  background: rgba(255,255,255,0.22);
  color: #fff;
}

/* Cards and inputs take an accent edge on hover/focus. */
.project-card:hover { border-color: var(--accent-line); }
.new-project-card:hover { border-color: var(--accent); color: var(--accent); }
.mode-row:hover:not(.mode-row-soon) { border-color: var(--accent-line); }
input:focus, textarea:focus, select:focus { border-color: var(--accent); }

/* Billing toggle savings dot. */
.billing-toggle-pill.has-savings-dot::after { background: var(--accent); }

/* Admin highlight cells. */
.admin-stat.highlight { border-color: var(--accent-line); }


/* --- Accent hovers on interactive surfaces -------------------------
   All of these read var(--accent), so each page gets its own colour
   automatically: orange in the Studio and Projects, blue on Home, pink
   on Pricing. No per-page rules to keep in sync. */

/* Studio inputs: upload zone, notes field, mode and project pickers.
   .upload-zone previously hovered to --moss (near-black), which is why
   it didn't pick up the accent with everything else. */
.upload-zone:hover,
.upload-zone.dragover {
  border-color: var(--accent);
  background: var(--accent-softer);
}
.mode-trigger:hover,
.select-field:hover {
  border-color: var(--accent);
}
.mode-trigger:focus-visible,
.select-field:focus {
  border-color: var(--accent);
  outline-color: var(--accent);
}
/* The notes field is borderless by default, so the accent arrives as a
   ring rather than a border colour — otherwise there's nothing to tint. */
.notes-textarea-borderless:hover,
.notes-textarea-borderless:focus {
  box-shadow: inset 0 0 0 1px var(--accent);
  outline: none;
}

/* Projects tab and Render History tiles. */
.project-card:hover {
  border-color: var(--accent);
  box-shadow: 0 6px 18px var(--accent-softer);
}
.new-project-card:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-softer);
}
.thumb-grid .render-tile:hover {
  border-color: var(--accent);
  box-shadow: 0 4px 14px var(--accent-softer);
}
.thumb-grid img:hover {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Main nav. Each destination hovers to ITS OWN page's accent rather than
   the accent of the page you're currently on — so Home always previews
   blue, Studio orange, Pricing pink, from anywhere in the app. That's
   why these are hardcoded per href instead of using var(--accent):
   the colour belongs to the target, not the current page. */
.nav-tab[href="/"]:hover:not(.active) {
  border-color: #06B6D4;
  color: #0E7490;
}
.nav-tab[href="/app"]:hover:not(.active) {
  border-color: #FF8A5B;
  color: #BF5A33;
}
.nav-tab[href="/pricing.html"]:hover:not(.active) {
  border-color: #FE019A;
  color: #C4017A;
}

/* --- Sitewide accent hovers (extended) -----------------------------
   All read var(--accent), so each page supplies its own colour. */

/* Account icon in the top-right — mint on the Account page, and the
   accent of whatever page you're on elsewhere. */
.nav-account-icon:hover {
  border-color: var(--accent);
  color: var(--accent-deep);
  background: var(--accent-softer);
}

/* Account page form fields. */
.profile-name-input:hover,
.profile-name-input:focus {
  border-color: var(--accent);
  outline: none;
}

/* Text inputs and textareas generally. */
input[type="text"]:hover,
input[type="email"]:hover,
input[type="password"]:hover,
input[type="number"]:hover,
textarea:hover,
select:hover {
  border-color: var(--accent-line);
}
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
textarea:focus,
select:focus {
  border-color: var(--accent);
}

/* Secondary buttons and nav-adjacent controls. */
.secondary-btn:hover { border-color: var(--accent); color: var(--accent-deep); }
.billing-toggle-pill:hover:not(.active) { color: var(--accent-deep); }
.credit-badge:hover { border-color: var(--accent-line); }

/* Render History: the reuse action and the tile itself. The base rules
   for these carry higher specificity, so these match it rather than
   relying on source order. */
.render-tile-actions .reuse-link:hover {
  color: var(--accent);
  text-decoration: underline;
}
.thumb-grid .render-tile:hover .render-tile-caption { color: var(--accent-deep); }

/* Footer links. */
.site-footer-links a:hover { color: var(--accent-deep); }
