/* ═══════════════════════════════════════════════════════════════════════════
   AD STUDIO — Bannerflow-parity banner editor (tool #31). Phase 1: shell,
   document model, canvas, inspector, timeline.

   ⚠ EVERYTHING IS SCOPED UNDER .as-app AND ITS TOKENS LIVE ON .as-app, NOT
   :root. This panel mounts inside a page carrying ~700KB of other tool CSS,
   and past tools here have been broken by exactly that collision. No bare
   element selectors, no :root, no !important except where a documented UA /
   site-global rule has to be beaten.

   Known site-globals this file must survive (all previously cost real time):
     • main.app section:not(.panel){padding-top:0} — (0,2,2), kills padding on
       any top-level <section>. THIS PANEL USES DIVS, not <section>.
     • textarea{height:165px} in the site style.css — beaten explicitly below.
     • .foo{display:flex} beats the UA [hidden] rule — every hideable node here
       re-asserts [hidden]{display:none!important}.
   ═══════════════════════════════════════════════════════════════════════════ */

.as-app,
/* ⚠ AND THE MODALS. Every dialog is appended to document.body — outside
   .as-app — so with the palette declared only on .as-app every var() inside
   .as-modal* resolved to NOTHING: the box lost its background to `initial`
   (transparent) and the accent button rendered with no fill at all. Declared
   in both places rather than copied, so the two can never drift. */
.as-modal{
  /* palette — OUR tokens, deliberately not a copy of Bannerflow's chrome */
  --as-bg:#f5f6f8; --as-panel:#fff; --as-line:#e4e7ec; --as-line-2:#eef0f3;
  --as-ink:#141820; --as-ink-2:#5c6473; --as-mute:#8b93a1;
  --as-accent:#5b5bd6; --as-accent-soft:#eeeeff;
  --as-canvas:#fafbfc;
  /* timeline bar colours, keyed to element type like Bannerflow does */
  --as-t-text:#8f8ff0; --as-t-button:#f0a35e; --as-t-image:#7fc9a0;
  --as-t-shape:#79b8e8;
  --as-rail-w:52px; --as-insp-w:264px; --as-tl-h:230px; --as-row-h:22px;

  display:flex; flex-direction:column;
  height:calc(100vh - 116px); min-height:560px;
  background:var(--as-bg); color:var(--as-ink);
  border:1px solid var(--as-line); border-radius:12px; overflow:hidden;
  font-size:13px; line-height:1.45;
}
.as-app *,.as-app *::before,.as-app *::after{box-sizing:border-box}
.as-app [hidden]{display:none!important}

/* ── top bar ─────────────────────────────────────────────────────────────── */
.as-top{display:flex;align-items:center;gap:12px;height:44px;flex:0 0 44px;
  padding:0 12px;background:var(--as-panel);border-bottom:1px solid var(--as-line)}
/* ⚠ nowrap + flex:none. The app bar is a flex row that gets tight at ~1000px,
   and the brand was both shrinking AND wrapping — "Ad" over "Studio", which
   reads as a broken logo rather than a cramped one. */
.as-top-brand{display:flex;align-items:center;gap:8px;font-weight:700;
              flex:none;white-space:nowrap}
/* the artwork IS the mark — no gradient chip behind it, same rule the rail follows */
/* ⚠ flex:none — .as-top-brand is a flex row, so a plain width:24px gets SHRUNK
   (it was landing at 22.17px and squashing the mark against its own height). */
.as-top-ico{flex:none;width:24px;height:24px;display:grid;place-items:center}
.as-top-ico img{width:100%;height:100%;object-fit:contain;display:block}
.as-crumb{color:var(--as-mute);font-weight:600}
.as-crumb b{color:var(--as-ink)}
.as-top-sp{flex:1}
.as-save{font-size:11px;font-weight:700;color:var(--as-mute);
  background:var(--as-line-2);border-radius:5px;padding:4px 9px}
.as-save.is-dirty{color:#8a6100;background:#fff4d6}

/* ── body: rail | canvas | inspector ─────────────────────────────────────── */
.as-body{flex:1;display:flex;min-height:0}

.as-rail{width:var(--as-rail-w);flex:0 0 var(--as-rail-w);background:var(--as-panel);
  border-right:1px solid var(--as-line);display:flex;flex-direction:column;
  align-items:center;gap:4px;padding:8px 0}
.as-tool{width:34px;height:34px;border-radius:8px;border:0;background:transparent;
  color:var(--as-ink-2);cursor:pointer;display:grid;place-items:center;font-size:14px;
  position:relative;transition:background .13s,color .13s}
.as-tool:hover{background:var(--as-line-2);color:var(--as-ink)}
.as-tool.is-on{background:var(--as-ink);color:#fff}
.as-tool[disabled]{opacity:.38;cursor:not-allowed}
.as-rail-sep{width:24px;height:1px;background:var(--as-line);margin:5px 0}
/* tooltip — Bannerflow labels every rail tool with name + shortcut, and that
   discoverability is half the point of the rail, so it is not optional here */
.as-tool::after{content:attr(data-tip);position:absolute;left:calc(100% + 9px);top:50%;
  transform:translateY(-50%);background:#20242c;color:#fff;font-size:11px;font-weight:600;
  white-space:nowrap;padding:5px 9px;border-radius:6px;opacity:0;pointer-events:none;
  transition:opacity .12s;z-index:40}
.as-tool:hover::after{opacity:1}

/* ── canvas ──────────────────────────────────────────────────────────────── */
.as-canvas-wrap{flex:1;min-width:0;display:flex;flex-direction:column;background:var(--as-canvas)}
.as-canvas-bar{display:flex;align-items:center;gap:8px;padding:7px 12px;
  border-bottom:1px solid var(--as-line-2)}
.as-canvas-bar .as-sp{flex:1}
.as-zoom{display:flex;align-items:center;gap:2px;background:var(--as-panel);
  border:1px solid var(--as-line);border-radius:7px;padding:2px}
.as-zoom button{border:0;background:transparent;width:24px;height:22px;cursor:pointer;
  color:var(--as-ink-2);border-radius:5px;font-size:13px}
.as-zoom button:hover{background:var(--as-line-2)}
.as-zoom span{min-width:46px;text-align:center;font-size:11px;font-weight:700}

.as-stage-scroll{flex:1;overflow:auto;display:grid;place-items:center;padding:28px}
.as-stage{position:relative;background:#fff;flex:none;
  box-shadow:0 1px 3px rgba(20,30,60,.14),0 8px 26px rgba(20,30,60,.10)}
.as-el{position:absolute;transform-origin:50% 50%}
.as-el-txt{display:flex;overflow:hidden;white-space:pre-wrap;word-break:break-word}
.as-el-img{display:block;width:100%;height:100%;object-fit:contain;pointer-events:none}
/* selection chrome lives OUTSIDE the element so a rotated element still gets an
   axis-aligned, grabbable handle box */
.as-sel{position:absolute;border:1.5px solid var(--as-accent);pointer-events:none;z-index:30}
.as-h{position:absolute;width:9px;height:9px;background:#fff;border:1.5px solid var(--as-accent);
  border-radius:2px;pointer-events:auto;z-index:31}
.as-h[data-h="nw"]{left:-5px;top:-5px;cursor:nwse-resize}
.as-h[data-h="ne"]{right:-5px;top:-5px;cursor:nesw-resize}
.as-h[data-h="sw"]{left:-5px;bottom:-5px;cursor:nesw-resize}
.as-h[data-h="se"]{right:-5px;bottom:-5px;cursor:nwse-resize}
.as-h[data-h="n"]{left:50%;top:-5px;margin-left:-4.5px;cursor:ns-resize}
.as-h[data-h="s"]{left:50%;bottom:-5px;margin-left:-4.5px;cursor:ns-resize}
.as-h[data-h="w"]{left:-5px;top:50%;margin-top:-4.5px;cursor:ew-resize}
.as-h[data-h="e"]{right:-5px;top:50%;margin-top:-4.5px;cursor:ew-resize}
.as-hover-ring{position:absolute;border:1px solid rgba(91,91,214,.5);pointer-events:none;z-index:29}

/* ── inspector ───────────────────────────────────────────────────────────── */
.as-insp{width:var(--as-insp-w);flex:0 0 var(--as-insp-w);background:var(--as-panel);
  border-left:1px solid var(--as-line);overflow-y:auto;overflow-x:hidden}
.as-insp-head{display:flex;align-items:center;gap:7px;padding:11px 12px;
  border-bottom:1px solid var(--as-line);position:sticky;top:0;background:var(--as-panel);z-index:5}
.as-insp-head b{font-size:12.5px}
.as-sec{border-bottom:1px solid var(--as-line-2);padding:11px 12px}
.as-sec-h{display:flex;align-items:center;justify-content:space-between;
  font-size:11px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;
  color:var(--as-mute);margin:0 0 9px}
.as-sec-h button{border:0;background:transparent;color:var(--as-accent);cursor:pointer;
  font-size:15px;line-height:1;padding:0 2px;font-weight:700}
.as-row{display:flex;align-items:center;gap:7px;margin-bottom:7px}
.as-row:last-child{margin-bottom:0}
.as-row label{flex:0 0 58px;color:var(--as-ink-2);font-size:11.5px}
.as-f{flex:1;min-width:0;display:flex;align-items:center;gap:4px;
  background:var(--as-bg);border:1px solid var(--as-line);border-radius:6px;padding:0 6px;height:27px}
.as-f input,.as-f select{flex:1;min-width:0;width:100%;border:0;background:transparent;
  font:inherit;font-size:12px;color:var(--as-ink);outline:0;height:25px;padding:0}
.as-f i{font-style:normal;color:var(--as-mute);font-size:10.5px;flex:none}
.as-f:focus-within{border-color:var(--as-accent);background:#fff}
/* ⚠ the site style.css sets a bare textarea{height:165px} — a 2-line box here
   would otherwise render six lines tall. Same bug the multiframe tool hit. */
.as-app textarea.as-ta{height:54px;min-height:54px;width:100%;resize:vertical;
  border:1px solid var(--as-line);border-radius:6px;background:var(--as-bg);
  font:inherit;font-size:12px;color:var(--as-ink);padding:6px 7px;line-height:1.4;outline:0}
.as-app textarea.as-ta:focus{border-color:var(--as-accent);background:#fff}
.as-sw{width:27px;height:25px;border-radius:5px;border:1px solid var(--as-line);
  cursor:pointer;padding:0;flex:none;background:#fff}
.as-seg{display:flex;gap:2px;background:var(--as-bg);border:1px solid var(--as-line);
  border-radius:6px;padding:2px;flex:1}
.as-seg button{flex:1;border:0;background:transparent;border-radius:4px;height:21px;
  cursor:pointer;color:var(--as-ink-2);font-size:11px;display:grid;place-items:center}
.as-seg button.is-on{background:var(--as-ink);color:#fff}
.as-empty{padding:22px 14px;color:var(--as-mute);font-size:12px;text-align:center}

/* ── timeline ────────────────────────────────────────────────────────────── */
.as-tl{height:var(--as-tl-h);flex:0 0 var(--as-tl-h);background:var(--as-panel);
  border-top:1px solid var(--as-line);display:flex;flex-direction:column;min-height:0}
.as-tl.is-collapsed{height:42px;flex-basis:42px}
.as-tl-bar{display:flex;align-items:center;gap:9px;padding:7px 12px;
  border-bottom:1px solid var(--as-line-2);flex:0 0 auto}
.as-tp{border:0;background:transparent;width:26px;height:24px;border-radius:5px;
  cursor:pointer;color:var(--as-ink-2);font-size:12px}
/* ⚠ THE APP-BAR ACTIONS ARE BIGGER THAN THE REST ON PURPOSE. Open, Save and
   Full page are the three things you reach for by eye, and at the shared 26x24
   they sat in a row of identical grey glyphs with nothing to aim at — the owner
   could not find them. A larger hit area, a visible resting surface and a border
   make them read as buttons rather than as decoration; every other .as-tp in the
   tool (rulers, zoom, layer menus) is untouched. */
/* ⚠ flex:none, or the same shrink that squashed the brand hits these — the +/−
   size buttons sit in a flex span and came out 23px wide against a declared 34,
   which is a lopsided row and a smaller target than before the change. */
.as-top .as-tp{flex:none;width:34px;height:32px;font-size:15px;border:1px solid var(--as-line-2);
  background:var(--as-panel);color:var(--as-ink-2)}
.as-top .as-tp:hover{background:var(--as-line-2);color:var(--as-ink);border-color:var(--as-line)}
.as-top .as-tp:active{transform:translateY(1px)}
.as-tp:hover{background:var(--as-line-2);color:var(--as-ink)}
.as-tp.is-on{color:var(--as-accent)}
.as-time{font-variant-numeric:tabular-nums;font-size:11.5px;font-weight:700;
  color:var(--as-ink-2);min-width:88px}
.as-tl-main{flex:1;display:flex;min-height:0}
.as-tl-names{width:168px;flex:0 0 168px;border-right:1px solid var(--as-line);
  overflow:hidden auto}
.as-tl-tracks{flex:1;position:relative;overflow:auto}
.as-tl-ruler{height:22px;position:sticky;top:0;background:var(--as-panel);z-index:6;
  border-bottom:1px solid var(--as-line-2)}
.as-tick{position:absolute;top:0;bottom:0;width:1px;background:var(--as-line)}
.as-tick.is-sec{background:#cfd5de}
.as-tick-lb{position:absolute;top:4px;font-size:9.5px;color:var(--as-mute);
  transform:translateX(3px)}
.as-names-pad{height:22px;border-bottom:1px solid var(--as-line-2)}
.as-lrow{height:var(--as-row-h);display:flex;align-items:center;gap:6px;padding:0 8px;
  cursor:pointer;font-size:11.5px;color:var(--as-ink-2)}
.as-lrow:hover{background:var(--as-line-2)}
.as-lrow.is-sel{background:var(--as-accent-soft);color:var(--as-ink);font-weight:600}
.as-lrow .as-eye{border:0;background:transparent;cursor:pointer;color:var(--as-mute);
  font-size:10px;padding:0;width:14px;flex:none}
.as-lrow .as-nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.as-trow{height:var(--as-row-h);position:relative}
.as-trow.is-sel{background:var(--as-accent-soft)}
/* the life-span bar; ::before/::after are the in/out animation segments, which is
   how Bannerflow labels each end of the bar */
.as-bar{position:absolute;top:3px;height:calc(var(--as-row-h) - 6px);border-radius:3px;
  background:var(--as-t-shape);cursor:grab;display:flex;align-items:center;
  justify-content:space-between;overflow:hidden;font-size:9.5px;color:#fff;font-weight:700}
.as-bar[data-t="text"]{background:var(--as-t-text)}
.as-bar[data-t="button"]{background:var(--as-t-button)}
.as-bar[data-t="image"]{background:var(--as-t-image)}
.as-seg-in,.as-seg-out{background:rgba(0,0,0,.19);height:100%;display:flex;align-items:center;
  padding:0 4px;white-space:nowrap;overflow:hidden;max-width:48%}
.as-playhead{position:absolute;top:0;bottom:0;width:1px;background:var(--as-accent);
  z-index:8;pointer-events:none}
.as-playhead::before{content:"";position:absolute;top:0;left:-4px;width:9px;height:9px;
  background:var(--as-accent);border-radius:2px}

/* layer-row controls — hidden until the row is hovered or selected so the list
   stays quiet at rest, which matters when a creative has 15 layers */
.as-lrow .as-more{border:0;background:transparent;cursor:pointer;color:var(--as-mute);
  font-size:11px;padding:0;width:14px;flex:none;opacity:0;transition:opacity .12s}
.as-lrow:hover .as-more,.as-lrow.is-sel .as-more{opacity:1}
.as-lrow .as-eye{opacity:.45;transition:opacity .12s}
.as-lrow:hover .as-eye,.as-lrow.is-sel .as-eye{opacity:1}
.as-app input.as-rename{flex:1;min-width:0;border:1px solid var(--as-accent);border-radius:4px;
  background:#fff;font:inherit;font-size:11.5px;color:var(--as-ink);height:18px;padding:0 4px;outline:0}

/* ⚠ THE LAYER MENU IS APPENDED TO document.body, NOT INSIDE THE TIMELINE.
   The timeline panes are overflow:auto, so a menu rendered inside a row gets
   clipped by the scroller the moment it is taller than the row — which is
   always. Positioning is therefore fixed, from the anchor's viewport rect. */
.as-menu{position:fixed;z-index:9999;background:#fff;border:1px solid var(--as-line);
  border-radius:8px;box-shadow:0 10px 30px rgba(20,30,60,.18);padding:4px;min-width:168px}
.as-menu button{display:flex;align-items:center;gap:9px;width:100%;border:0;background:transparent;
  font:inherit;font-size:12px;color:var(--as-ink);text-align:left;padding:7px 9px;
  border-radius:6px;cursor:pointer}
.as-menu button:hover:not([disabled]){background:var(--as-line-2)}
.as-menu button[disabled]{opacity:.36;cursor:not-allowed}
.as-menu button i{width:13px;text-align:center;color:var(--as-mute);font-size:11px}

@media(max-width:1100px){
  .as-app{--as-insp-w:224px;--as-tl-h:196px}
}

/* ── creative-set switcher ───────────────────────────────────────────────── */
.as-sizes{display:flex;align-items:center;gap:2px;margin-left:6px}
.as-sizes select{border:1px solid var(--as-line);background:var(--as-bg);border-radius:6px;
  font:inherit;font-size:11.5px;font-weight:600;color:var(--as-ink);height:26px;padding:0 6px;
  outline:0;cursor:pointer;max-width:120px}
.as-sizes select:focus{border-color:var(--as-accent);background:#fff}
.as-menu-sizes{max-height:360px;overflow:auto;min-width:186px}
/* a locked preset stays READABLE — greying it out would read as "broken", and the
   point is to show what PRO adds, not to hide it */
.as-menu button[data-locked] i{color:var(--as-accent)}
.as-pro{margin-left:auto;font-size:9px;font-weight:800;letter-spacing:.4px;
  background:var(--as-accent);color:#fff;border-radius:4px;padding:1px 4px}
.as-menu-sep{height:1px;background:var(--as-line);margin:4px 2px}
.as-menu-note{padding:5px 9px 7px;font-size:10.5px;line-height:1.45;color:var(--as-mute)}
.as-cust{padding:4px 6px 7px}
.as-cust-row{display:flex;align-items:center;gap:5px}
.as-cust-row span{color:var(--as-mute);font-size:11px}
.as-cust input{width:100%;min-width:0;border:1px solid var(--as-line);border-radius:6px;
  background:var(--as-bg);font:inherit;font-size:12px;color:var(--as-ink);height:26px;padding:0 6px;outline:0}
.as-cust input:focus{border-color:var(--as-accent);background:#fff}
.as-cust-go{width:auto!important;flex:0 0 auto;background:var(--as-accent)!important;color:#fff;
  font-weight:700;padding:0 10px!important;height:26px}
.as-cust-go:hover{filter:brightness(1.08)}
.as-cust-msg{margin-top:5px;font-size:10.5px;color:var(--as-mute)}
.as-cust-msg.is-bad{color:#c0392b}
.as-insp-size{margin-left:auto;font-size:10.5px;font-weight:700;color:var(--as-accent);
  background:var(--as-accent-soft);border-radius:5px;padding:2px 6px}
/* "this size only" — without it, a user edits X at 728×90, switches to 300×250,
   sees the old value and concludes the tool lost the edit */
.as-hint{font-style:normal;font-size:9.5px;font-weight:700;letter-spacing:0;
  text-transform:none;color:var(--as-accent)}

/* ── DARK MODE ───────────────────────────────────────────────────────────────
   The studio has a site-wide dark toggle (core/dark-tools.css, scoped to
   html.dark) and it was reaching this panel's inputs while the panel's own
   surfaces stayed light — inspector dark, canvas light, in one editor. Because
   every colour here is a token, dark mode is a token swap and nothing else.
   ⚠ The CANVAS STAGE is deliberately NOT re-tinted: it shows the actual ad, and
   an ad does not change colour because the editor chrome did. Only the chrome
   flips; the creative renders as it will ship. */
html.dark .as-app{
  --as-bg:#14181e; --as-panel:#191e26; --as-line:#2a3038; --as-line-2:#22272f;
  --as-ink:#e8ebf2; --as-ink-2:#a9b2c1; --as-mute:#79838f;
  --as-accent:#8b8bf5; --as-accent-soft:#252542;
  --as-canvas:#101318;
}
html.dark .as-app .as-tool.is-on{background:var(--as-accent);color:#fff}
html.dark .as-app .as-sw{border-color:var(--as-line)}
html.dark .as-menu{background:#191e26;border-color:#2a3038;
  box-shadow:0 10px 30px rgba(0,0,0,.55)}
html.dark .as-menu button{color:#e8ebf2}
html.dark .as-menu button:hover:not([disabled]){background:#22272f}
html.dark .as-app .as-save.is-dirty{color:#ffd27a;background:#3a2f12}
/* the stage keeps its own white/authored background — see the note above */
html.dark .as-app .as-stage{box-shadow:0 1px 3px rgba(0,0,0,.5),0 8px 26px rgba(0,0,0,.45)}

/* ── MANAGE VIEW (the "Sizes" board) ─────────────────────────────────────────
   Design view shows canvas + inspector; Sizes view shows the grid + the bulk
   content panel. Both sets of panes exist in the DOM and the body class picks
   which pair is live, so switching does not rebuild the whole panel. */
.as-viewtabs{display:flex;gap:2px;background:var(--as-bg);border:1px solid var(--as-line);
  border-radius:7px;padding:2px;margin-left:8px}
.as-viewbtn{display:inline-flex;align-items:center;gap:6px;border:0;background:transparent;
  font:inherit;font-size:11.5px;font-weight:700;color:var(--as-ink-2);cursor:pointer;
  padding:4px 10px;border-radius:5px}
.as-viewbtn i{font-size:10px}
.as-viewbtn.is-on{background:var(--as-ink);color:#fff}

.as-grid{display:none}
.as-bulk{display:none}
.as-body.as-view-sizes .as-canvas-wrap{display:none}
.as-body.as-view-sizes .as-insp:not(.as-bulk){display:none}
.as-body.as-view-sizes .as-grid{display:block;flex:1;min-width:0;overflow:auto;
  padding:18px;background:var(--as-canvas)}
.as-body.as-view-sizes .as-bulk{display:block}

.as-grid{align-content:start}
/* ⚠ align-items:start — grid items default to STRETCH, so a 728×90 card sharing
   a row with a 300×250 was pulled to the taller card's height and rendered a
   31px strip floating in a sea of empty panel. Each card must be its own height. */
.as-body.as-view-sizes .as-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:16px;align-items:start}
.as-card{background:var(--as-panel);border:1px solid var(--as-line);border-radius:10px;
  overflow:hidden;box-shadow:0 1px 2px rgba(20,30,60,.06)}
.as-card.is-active{border-color:var(--as-accent);box-shadow:0 0 0 2px var(--as-accent-soft)}
.as-card-h{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:8px 11px;border-bottom:1px solid var(--as-line-2);font-size:11.5px;color:var(--as-ink-2)}
.as-card-h b{color:var(--as-ink);font-size:11.5px}
.as-card-open{border:0;background:transparent;color:var(--as-mute);cursor:pointer;
  font-size:11px;padding:3px 5px;border-radius:5px}
.as-card-open:hover{background:var(--as-line-2);color:var(--as-accent)}
/* the card body is a fixed-height window; the inner node is the ad at its TRUE
   pixel size, scaled down — so what you see is the real layout, not a re-flow */
.as-card-stage{position:relative;overflow:hidden;display:flex;align-items:flex-start;
  justify-content:center;background:var(--as-bg)}
.as-card-inner{position:relative;transform-origin:top center;flex:none}

.as-bulk-note{padding:10px 12px;font-size:11.5px;color:var(--as-mute);
  border-bottom:1px solid var(--as-line-2)}
.as-bulk-i{margin-bottom:10px}
.as-bulk-i:last-child{margin-bottom:0}
.as-bulk-i label{display:block;font-size:11px;font-weight:700;color:var(--as-ink-2);margin-bottom:4px}
html.dark .as-app .as-card{background:#191e26;border-color:#2a3038}

/* ── export + weights ────────────────────────────────────────────────────── */
.as-exp{display:inline-flex;align-items:center;gap:7px;border:0;border-radius:7px;cursor:pointer;
  background:var(--as-accent);color:#fff;font:inherit;font-size:12px;font-weight:700;
  padding:6px 13px}
.as-exp:hover{filter:brightness(1.07)}
.as-exp[disabled]{opacity:.6;cursor:default}
.as-btn{width:100%;border:1px solid var(--as-line);background:var(--as-bg);border-radius:7px;
  font:inherit;font-size:12px;font-weight:600;color:var(--as-ink);padding:7px;cursor:pointer}
.as-btn:hover{border-color:var(--as-accent);color:var(--as-accent)}
.as-note{font-size:10.5px;color:var(--as-mute);margin-top:7px;line-height:1.5}
.as-wt{width:100%;border-collapse:collapse;font-size:11px;font-variant-numeric:tabular-nums}
.as-wt td{padding:4px 3px;border-bottom:1px solid var(--as-line-2);color:var(--as-ink-2)}
.as-wt td:first-child{color:var(--as-ink);font-weight:600}
.as-wt td:last-child{text-align:right;color:var(--as-ink)}
.as-wt tr.over td{color:#c2410c}
html.dark .as-app .as-wt tr.over td{color:#ff9d6b}
.as-chk{display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--as-ink-2);
  margin-top:9px;cursor:pointer}
.as-chk input{margin:0;cursor:pointer}

/* ── hex field ───────────────────────────────────────────────────────────── */
.as-hexf{flex:0 0 84px;max-width:84px}
.as-hexf input{text-transform:lowercase;font-variant-numeric:tabular-nums;letter-spacing:.02em}

/* ── on-canvas image toolbar ─────────────────────────────────────────────────
   Anchored under the selected image, INSIDE the stage so it tracks the element
   as it moves. pointer-events must be re-enabled: the selection chrome above it
   is pointer-events:none and the bar would otherwise inherit nothing clickable. */
.as-imgbar{position:absolute;z-index:34;display:flex;align-items:center;gap:2px;
  transform:translateY(7px);background:#20242c;border-radius:8px;padding:3px;
  box-shadow:0 6px 20px rgba(10,15,30,.34);white-space:nowrap;pointer-events:auto}
.as-imgbar button{border:0;background:transparent;color:#dfe4ec;font:inherit;font-size:11px;
  font-weight:600;padding:4px 8px;border-radius:5px;cursor:pointer;line-height:1.3}
.as-imgbar button:hover{background:#333a46;color:#fff}
.as-imgbar button[disabled]{opacity:.5;cursor:default}
.as-ib-meta{color:#98a2b3;font-size:10px;font-weight:600;padding:0 7px 0 6px;
  border-right:1px solid #333a46;margin-right:3px}
.as-ib-warn{color:#ffb26b;font-weight:800}
/* the bar must not be clipped by the stage; the stage has no overflow rule, but
   a bar on a bottom-edge image would still sit outside the visible scroll area,
   so the scroller keeps room via its existing padding */
.as-toast{position:absolute;left:50%;bottom:18px;transform:translateX(-50%);z-index:60;
  background:#20242c;color:#fff;font-size:12px;font-weight:600;padding:9px 15px;
  border-radius:8px;box-shadow:0 8px 26px rgba(10,15,30,.4);pointer-events:none}
.as-canvas-wrap{position:relative}
/* ⚠ THE RULERS' CONTAINING BLOCK — it must start BELOW the zoom bar, which is
   what .as-canvas-wrap did not do: an abspos child of a flex column takes its
   static position from the container's content-box corner, so both rulers landed
   on top of the bar. min-height:0 so the scroller inside can actually shrink. */
.as-canvas-body{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}

/* ── rotate handle ───────────────────────────────────────────────────────────
   Sits above the top edge INSIDE the rotated selection box, so it orbits with
   the element and always reads as attached to it rather than to the screen.
   pointer-events must be re-enabled — .as-sel is pointer-events:none so clicks
   fall through to the canvas, and the handle is the exception. */
.as-rot{position:absolute;left:50%;top:-27px;margin-left:-11px;width:22px;height:22px;
  border-radius:50%;background:#fff;border:1.5px solid var(--as-accent);color:var(--as-accent);
  display:grid;place-items:center;font-size:9px;cursor:grab;pointer-events:auto;z-index:33;
  box-shadow:0 1px 4px rgba(20,30,60,.24)}
.as-rot:hover{background:var(--as-accent);color:#fff}
/* ⚠ TOP-RIGHT, clear of the rotate grip at top-CENTRE — two controls a few px
   apart, one destructive, is how you delete the layer you meant to turn. Same
   z and pointer-events as .as-rot so it is clickable inside the chrome layer,
   which is pointer-events:none for everything else. */
.as-x{position:absolute;right:-11px;top:-11px;width:22px;height:22px;
  border-radius:50%;background:#fff;border:1.5px solid var(--as-danger,#dc2626);
  color:var(--as-danger,#dc2626);display:grid;place-items:center;font-size:10px;
  cursor:pointer;pointer-events:auto;z-index:34;box-shadow:0 1px 4px rgba(20,30,60,.24)}
.as-x:hover{background:var(--as-danger,#dc2626);color:#fff}

/* Reset is destructive, so it reads warm on hover instead of looking like a
   sibling of Undo. Not red at rest — it is not an emergency, just irreversible
   without undo. */
/* Saved-creatives dialog */
.as-modal{position:fixed;inset:0;background:rgba(12,16,26,.46);z-index:99992;display:grid;place-items:center;padding:20px}
.as-modal-box{background:var(--as-panel);border:1px solid var(--as-line);border-radius:12px;
  width:min(460px,100%);max-height:min(70vh,560px);overflow:auto;box-shadow:0 18px 50px rgba(10,15,30,.28)}
.as-modal-h{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--as-line-2);
  font-size:13px;position:sticky;top:0;background:var(--as-panel)}
.as-modal-h b{font-weight:750;color:var(--as-ink)}
.as-modal-h em{font-style:normal;font-size:11px;color:var(--as-mute);margin-right:auto}
.as-files{padding:6px}
/* client → campaign folder heading. The flat list was fine at five saves and
   unreadable at fifty; the fields are already on every row so the title is free. */
.as-fgrp{margin-bottom:10px}
.as-fgrp:last-child{margin-bottom:0}
.as-fgrp-h{display:flex;align-items:center;gap:8px;padding:6px 8px 5px;
  font-size:11.5px;font-weight:800;letter-spacing:.02em;color:#6b7690}
.as-fgrp-h i{font-size:11px;color:#8b93ff}
.as-fgrp-h b{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:12.5px;font-weight:800;letter-spacing:-.01em;color:#16233c}
.as-fgrp-h em{flex:none;font-style:normal;font-weight:800;opacity:.7}
/* month + campaign, indented under the client so the nesting reads at a glance */
.as-fmon{display:flex;align-items:center;gap:7px;padding:5px 8px 4px 20px;
  font-size:11.5px;font-weight:800;color:#6b7690}
.as-fmon i{font-size:10.5px;color:#8b93ff}
.as-fmon em,.as-fcmp em{margin-left:auto;font-style:normal;font-weight:800;opacity:.65}
.as-fcmp{display:flex;align-items:center;padding:4px 8px 3px 32px;
  font-size:11.5px;font-weight:700;color:#8b95a8}
/* the fourth level: folders inside a campaign. Indented past the campaign so the
   nesting reads at a glance; loose items stay at the campaign's own indent. */
.as-ffld{display:flex;align-items:center;gap:6px;margin:4px 0 2px 44px;font-size:11.5px;
  font-weight:650;color:var(--as-ink-2)}
.as-ffld i{font-size:10px;color:var(--as-mute)}
.as-ffld em{margin-left:auto;font-style:normal;font-size:10.5px;color:var(--as-mute)}
/* ⚠ flex:none, ALWAYS, on a button inside a flex row. .as-tp sets a width and
   nothing else; a long folder name would otherwise shrink the trash to a sliver
   — the same way .as-btn's width:100% once crushed .as-file-m to zero. */
.as-ffld .as-tp{flex:none;width:22px;height:20px;font-size:10.5px;margin-left:2px}
/* ⚠ DIMMED, NEVER HIDDEN. Hover-to-reveal would make "empty this folder"
   unreachable on a touch screen, where there is no hover at all. */
.as-ffld .as-tp{opacity:.45;transition:opacity .12s ease}
.as-fgf:hover .as-ffld .as-tp,.as-ffld .as-tp:focus-visible{opacity:1}
.as-ffld + .as-fcre .as-file,.as-ffld ~ .as-fcre .as-file{margin-left:56px}
.as-fgrp .as-file{margin-left:32px}
html.dark .as-fmon{color:#8b95a8}
html.dark .as-fcmp{color:#6b7690}
html.dark .as-fgrp-h b{color:#e7ebf2}
html.dark .as-fgrp-h{color:#8b95a8}
.as-file{display:flex;align-items:center;gap:9px;padding:9px 8px;border-radius:8px}
.as-file:hover{background:var(--as-line-2)}
.as-file-m{flex:1;min-width:0}
/* ⚠ .as-btn IS width:100% BY DEFAULT — it is the full-width button used in panels.
   Inside this flex ROW that makes it claim the whole line, and .as-file-m (flex:1,
   min-width:0) collapses to ZERO: the name and meta then wrap one word per line and
   the row is 158px tall. Latent since the dialog was written — the saved-creatives
   store was empty until someone finally saved one, so no row had ever rendered. */
.as-file .as-btn{width:auto;flex:none}
.as-file .as-tp{flex:none}

/* ── A CREATIVE IS A FOLDER OF ITS SIZES ──────────────────────────────────
   One saved record, shelved as a folder. The sizes are siblings of the row,
   not children — the row is a flex line and a stack inside it would be a
   second layout fighting the first. */
.as-fcre{border-radius:8px}
.as-fcre.is-open{background:var(--as-bg)}
.as-fcre-t{flex:none;width:20px;transition:transform .12s ease}
.as-fcre.is-open .as-fcre-t{transform:rotate(90deg)}
.as-fsizes{margin:0 0 6px 60px;display:flex;flex-wrap:wrap;gap:6px}
/* ⚠ AN AUTHOR `display` BEATS THE UA'S [hidden]{display:none} — same specificity,
   author sheet wins — so setting .hidden on this panel did NOTHING and every
   creative showed its sizes at once. The property said hidden; the pixels did not.
   Any element given a display in this file needs its own [hidden] rule. */
.as-fsizes[hidden]{display:none}
.as-fsz{display:flex;align-items:center;gap:7px;padding:6px 10px;border-radius:7px;
  border:1px solid var(--as-line);background:var(--as-panel);color:var(--as-ink);
  font:inherit;font-size:12px;cursor:pointer;width:auto}
.as-fsz:hover{border-color:var(--as-accent);background:var(--as-accent-soft)}
.as-fsz i{color:var(--as-mute);font-size:10px}
.as-fsz b{font-weight:650}
.as-fsz em{font-style:normal;color:var(--as-mute);font-size:11px}
@media (max-width:520px){.as-fsizes{margin-left:32px}.as-fsz em{display:none}}

/* ── SAVE DIALOG ──────────────────────────────────────────────────────────
   Replaces prompt(). Wider than the stock modal box because it carries two
   columns; .as-modal-box is width:min(460px,…) so the width is overridden
   HERE and not by editing the shared box every other dialog uses. */
.as-modal-box.as-sv{width:min(560px,94vw);display:flex;flex-direction:column;overflow:hidden}   /* two classes on purpose: .as-modal-box
   sets width:min(460px,100%) and is declared TWICE in this file, once after this
   block — at equal specificity the later one wins and the dialog stayed 460px. */
.as-sv-b{padding:14px 16px;flex:1 1 auto;min-height:0;overflow:auto}
/* ⚠ THE BOX SCROLLS TOO. .as-modal-box is max-height:min(70vh,560px);overflow:auto,
   so with a scrolling body as well the footer was pushed below the box's own fold
   and Save could not be reached at all. The box is a flex COLUMN here and the body
   is the only scroller, which pins the footer where it belongs. */
.as-sv-l{display:block;font-size:11px;font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;color:var(--as-mute);margin:0 0 5px}
.as-sv-l2{margin-top:15px}
.as-sv-b input[type=text],.as-sv-b select{width:100%;box-sizing:border-box;
  border:1px solid var(--as-line);background:var(--as-bg);color:var(--as-ink);
  border-radius:7px;padding:8px 9px;font:inherit;font-size:13px}
.as-sv-b input[type=text]:focus,.as-sv-b select:focus{outline:2px solid var(--as-accent);outline-offset:-1px}
.as-sv-two{display:grid;grid-template-columns:1fr 1fr;gap:11px;margin-top:12px}
@media (max-width:520px){.as-sv-two{grid-template-columns:1fr}}
.as-sv-note{display:flex;gap:7px;margin:9px 0 0;font-size:11.5px;line-height:1.45;color:var(--as-ink-2)}
.as-sv-note i{margin-top:2px;flex:none}
.as-sv-r{display:flex;gap:9px;align-items:flex-start;padding:9px 10px;margin-bottom:6px;
  border:1px solid var(--as-line);border-radius:8px;cursor:pointer}
.as-sv-r:has(input:checked){border-color:var(--as-accent);background:var(--as-bg)}
.as-sv-r input{margin:2px 0 0;flex:none;accent-color:var(--as-accent)}
.as-sv-r span{display:block;font-size:13px;color:var(--as-ink);min-width:0}
.as-sv-r em{display:block;font-style:normal;font-size:11.5px;color:var(--as-ink-2);margin-top:2px}
.as-sv-r input:disabled{opacity:.4}
.as-sv-r:has(input:disabled){opacity:.55;cursor:default}
.as-sv-f{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;flex:none;
  border-top:1px solid var(--as-line);background:var(--as-panel)}
/* ⚠ same trap as the file rows: .as-btn is width:100% by default */
.as-sv-f .as-btn{width:auto;flex:none;padding:8px 16px}

/* ── asConfirm ────────────────────────────────────────────────────────────
   Narrower than the save dialog: a question, not a form. Shares .as-sv-f for
   the footer so the two can never disagree about button sizing. */
.as-modal-box.as-cf{width:min(420px,94vw)}
.as-cf-b{padding:14px 16px}
.as-cf-b p{margin:0 0 8px;font-size:13px;line-height:1.5;color:var(--as-ink-2)}
.as-cf-b p:last-child{margin-bottom:0}
/* the link row in the "Preview link ready" dialog */
.as-lk{display:flex;gap:8px;align-items:center}
.as-lk input{flex:1;min-width:0}
.as-lk .as-btn{width:auto;flex:none;padding:8px 12px}
.as-sv-f a.as-btn{text-decoration:none;display:inline-flex;align-items:center}
.as-btn-danger{background:var(--as-danger,#dc2626);color:#fff;border-color:var(--as-danger,#dc2626)}
.as-btn-danger:hover:not([disabled]){filter:brightness(1.08);color:#fff}
.as-file-m b{display:block;font-size:12.5px;font-weight:700;color:var(--as-ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.as-file-m span{font-size:10.5px;color:var(--as-mute)}
/* someone else's file: show WHY there is no delete rather than an empty gap */
/* the "ask for a campaign" row at the foot of the Open dialog */
.as-req{border-top:1px solid var(--as-line-2);padding:11px 14px;display:grid;gap:7px}
.as-req label{font-size:11px;font-weight:700;color:var(--as-ink-2)}
.as-req-row{display:flex;gap:7px}
.as-req-row select{flex:1;min-width:0;font-size:11.5px;padding:5px 7px}
.as-req-pend{font-size:11px;line-height:1.5;color:var(--as-mute)}
.as-file-lock{width:26px;height:24px;display:grid;place-items:center;
  color:var(--as-mute);opacity:.55;font-size:11px}
.as-tp-warn:hover{background:rgba(220,38,38,.10);color:var(--as-danger,#dc2626)}
.as-tp:disabled{opacity:.32;cursor:default}
.as-tp:disabled:hover{background:transparent;color:var(--as-ink-2)}

/* Empty-canvas hint. In the chrome layer, which is pointer-events:none — drawing
   a box straight through it must keep working.
   ⚠ IT CARRIES ITS OWN CARD AND FIXED COLOURS, NOT THEME TOKENS. This sits on the
   AD's background, which is whatever the author set — the first cut used
   --as-mute/--as-ink-2 and vanished into the sample's near-black #0c0f14. The
   stage is deliberately never re-tinted for dark mode either (it shows the real
   ad), so tokens are the wrong source here: a light card with dark type reads on
   any backdrop, and the border keeps it defined on a white one. */
.as-blank{position:absolute;inset:0;display:grid;place-content:center;justify-items:center;
  pointer-events:none;padding:14px}
.as-blank>*{grid-column:1}
.as-blank{--hint-ink:#2c3446; --hint-mute:#5c6678}
.as-blank::before{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(268px,92%);height:min(150px,92%);border-radius:12px;
  background:rgba(255,255,255,.94);border:1px solid rgba(20,30,60,.10);
  box-shadow:0 2px 14px rgba(10,15,30,.16)}
.as-blank i,.as-blank b,.as-blank span{position:relative}
.as-blank i{font-size:16px;color:var(--hint-mute);opacity:.75;margin-bottom:5px}
.as-blank b{font-size:13px;font-weight:750;color:var(--hint-ink);margin-bottom:3px}
.as-blank span{font-size:11px;line-height:1.5;max-width:212px;color:var(--hint-mute);text-align:center}
.as-blank em{font-style:normal;font-weight:700;color:var(--hint-ink)}
.as-blank-k{font-size:9.5px;letter-spacing:.09em;opacity:.6;margin-top:5px}

/* the scroller while an image is over it */
.as-dropping{outline:2px dashed var(--as-accent);outline-offset:-6px;
  background:color-mix(in srgb,var(--as-accent) 6%,transparent)}
.as-rot:active{cursor:grabbing}
/* the stalk connecting the handle to the box, so it reads as one control */
.as-rot::after{content:"";position:absolute;top:20px;left:50%;width:1.5px;height:8px;
  margin-left:-.75px;background:var(--as-accent)}
.as-rot-lb{position:absolute;left:50%;top:-52px;transform:translateX(-50%);z-index:35;
  background:#20242c;color:#fff;font-size:10.5px;font-weight:700;padding:3px 7px;
  border-radius:5px;pointer-events:none;font-variant-numeric:tabular-nums}
.as-imgbar .as-ib-on{background:var(--as-accent);color:#fff}
.as-imgbar .as-ib-on:hover{background:#7a7aeb;color:#fff}

/* ── the banner boundary ─────────────────────────────────────────────────────
   .as-art clips the creative to the ad's real frame, matching the exported
   #ad{overflow:hidden}. Without it an oversized layer paints past the edge and
   the editor lies about what will ship. .as-chrome carries the selection box,
   handles, rotate grip and image toolbar OUTSIDE that clip, because those sit
   above and below the element by design and must not be cropped with it.
   ⚠ .as-chrome must be pointer-events:none or it would blanket the artwork and
   swallow every click; its children re-enable it individually. */
.as-art{position:absolute;inset:0;overflow:hidden}
.as-chrome{position:absolute;inset:0;overflow:visible;pointer-events:none;z-index:28}
.as-chrome .as-h,.as-chrome .as-rot,.as-chrome .as-imgbar{pointer-events:auto}
/* board cards clip too, for the same reason */
.as-card-inner{overflow:hidden}

/* ── rulers & guides (Creative QA's model) ───────────────────────────────────
   Strips live OUTSIDE the scaled stage and are laid out in screen px, because
   the stage is transform:scaled by the zoom — ticks drawn in model units would
   drift from what the user sees the moment they zoom. */
.as-canvas-body.as-has-rulers .as-stage-scroll{margin:20px 0 0 20px}
.as-rul{position:absolute;background:var(--as-panel);z-index:12;overflow:hidden;
  font-variant-numeric:tabular-nums;pointer-events:auto;cursor:crosshair}
.as-rul-x{top:0;left:20px;right:0;height:20px;border-bottom:1px solid var(--as-line)}
.as-rul-y{top:20px;bottom:0;width:20px;border-right:1px solid var(--as-line)}
.as-rul .as-tk{position:absolute;background:#c3cad6}
.as-rul-x .as-tk{top:12px;bottom:0;width:1px}
.as-rul-y .as-tk{left:12px;right:0;height:1px}
.as-rul .as-tk.is-zero{background:var(--as-accent);width:1.5px}
.as-rul-y .as-tk.is-zero{height:1.5px;width:auto}
.as-rul u{position:absolute;font-size:8.5px;color:var(--as-mute);text-decoration:none;line-height:1}
.as-rul-x u{top:2px}
.as-rul-y u{left:2px;writing-mode:vertical-rl}
/* the corner where the two strips meet — without it the L reads as broken */
.as-canvas-body.as-has-rulers::before{content:"";position:absolute;width:20px;height:20px;
  background:var(--as-panel);border-right:1px solid var(--as-line);
  border-bottom:1px solid var(--as-line);z-index:13}

/* guides sit INSIDE the stage so they scale and scroll with the banner, but
   above the artwork and below the selection chrome */
.as-guides{position:absolute;inset:0;z-index:27;pointer-events:none}
.as-gd{position:absolute;background:#12b5a6;pointer-events:auto;display:block}
.as-gd-v{top:-2000px;bottom:-2000px;width:1px;cursor:ew-resize}
.as-gd-h{left:-2000px;right:-2000px;height:1px;cursor:ns-resize}
/* a 1px line is nearly ungrabbable — widen the hit area without widening the ink */
.as-gd::after{content:"";position:absolute}
.as-gd-v::after{top:0;bottom:0;left:-4px;width:9px}
.as-gd-h::after{left:0;right:0;top:-4px;height:9px}
html.dark .as-app .as-rul .as-tk{background:#3b434f}

/* ── image toolbar: two rows ─────────────────────────────────────────────────
   Nine actions plus the readout ran wider than most banners, so on a 300×250
   the bar overhung the ad it belongs to. Facts on top, actions beneath, and the
   actions WRAP rather than extend — the bar can grow downward, never sideways
   past the creative it annotates. */
/* ⚠ max-width must fit ALL the actions on ONE line, or flex-wrap turns "two
   rows" into five and the bar grows taller than the banner. 290px was too mean:
   it wrapped nine buttons into four sub-rows (95px tall). Sized to the actions
   instead — the bar may overhang a 300px banner slightly, which is far better
   than a column of buttons burying the ad below it. */
.as-imgbar{flex-direction:column;align-items:flex-start;gap:3px;max-width:none;width:max-content}
.as-ib-r1{display:flex;align-items:center;padding:1px 4px 0}
.as-ib-r2{display:flex;align-items:center;gap:2px;flex-wrap:wrap}
.as-imgbar .as-ib-meta{border-right:0;margin:0;padding:0}

/* ── full page ───────────────────────────────────────────────────────────────
   A CSS overlay rather than the Fullscreen API: the browser's own fullscreen
   hides the tab strip and swallows Esc for its own exit, and a user who cannot
   find their way back out of an editor does not try it twice. */
.as-app.as-full{position:fixed;inset:0;z-index:9990;height:100vh;min-height:0;
  border-radius:0;border:0}
/* the studio shell owns the page scroll; lock it or the page drifts underneath */
body.as-body-full{overflow:hidden}

/* ── optimise panel ──────────────────────────────────────────────────────── */
.as-optp{width:238px;padding:11px 12px 10px}
.as-optp-h{font-size:11px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;
  color:var(--as-mute);margin-bottom:9px}
.as-optp-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.as-optp-row label{font-size:11.5px;color:var(--as-ink-2);flex:none}
.as-optp-row input[type=range]{flex:1;min-width:0;accent-color:var(--as-accent)}
.as-optp-row b{font-size:11.5px;font-variant-numeric:tabular-nums;min-width:20px;text-align:right}
.as-optp-est{font-size:11px;color:var(--as-ink-2);line-height:1.45;min-height:30px;
  background:var(--as-bg);border-radius:6px;padding:6px 8px;margin-bottom:9px}
.as-optp-act{display:flex;gap:6px}
.as-optp-act .as-btn{padding:6px}
.as-btn-go{background:var(--as-accent);color:#fff;border-color:var(--as-accent)}
.as-btn-go:hover:not([disabled]){filter:brightness(1.07);color:#fff}
.as-btn-go[disabled]{opacity:.5;cursor:default}
/* text style toggles sit in the same segmented control the aligns use */
.as-seg button s,.as-seg button u{text-decoration-thickness:1px}

/* ── align row (inspector) ─────────────────────────────────────────────────── */
.as-alignrow{display:flex;align-items:center;gap:3px;margin:0 0 8px}
.as-alignrow button{flex:1 1 0;min-width:0;height:26px;border:1px solid var(--as-line);
  background:var(--as-bg);border-radius:6px;color:var(--as-ink);font-size:11px;cursor:pointer;
  display:grid;place-items:center;padding:0}
.as-alignrow button:hover{background:var(--as-accent);border-color:var(--as-accent);color:#fff}
.as-alignsep{flex:0 0 1px;height:16px;background:var(--as-line);margin:0 3px}

/* ── export menu ───────────────────────────────────────────────────────────── */
.as-menu-exp{min-width:230px;padding:5px}
.as-menu-exp button{display:flex;align-items:flex-start;gap:9px;width:100%;border:0;background:transparent;
  font:inherit;font-size:12.5px;font-weight:600;color:var(--as-ink);text-align:left;padding:8px 9px;
  border-radius:7px;cursor:pointer;flex-wrap:wrap}
.as-menu-exp button:hover{background:var(--as-line-2)}
.as-menu-exp button i{width:14px;text-align:center;color:var(--as-accent);margin-top:2px}
.as-menu-exp small{display:block;width:100%;padding-left:23px;margin-top:1px;
  font-size:10.5px;font-weight:500;color:var(--as-mute)}

.as-lockar{display:flex;align-items:center;gap:6px;margin:-2px 0 8px;font-size:11.5px;
  color:var(--as-ink);cursor:pointer;user-select:none}
.as-lockar input{margin:0;cursor:pointer}
.as-lockar em{font-style:normal;color:var(--as-mute);font-size:10.5px}

/* extra members of a multi-selection: outline only, no handles */
.as-sel-more{border-style:dashed;opacity:.85}
.as-alignrow button[disabled]{opacity:.35;cursor:not-allowed}
.as-alignrow button[disabled]:hover{background:var(--as-bg);border-color:var(--as-line);color:var(--as-ink)}

/* rubber-band selection box — lives in the UNCLIPPED chrome layer, which is
   pointer-events:none, so it can never swallow the drag that is drawing it */
.as-marquee{position:absolute;border:1px solid var(--as-accent);
  background:rgba(91,91,214,.10);pointer-events:none;z-index:29}

.as-btn-wide{width:100%;justify-content:center}
.as-mini{margin-left:auto;border:1px solid var(--as-line);background:var(--as-bg);border-radius:5px;
  font:inherit;font-size:10.5px;font-weight:600;color:var(--as-mute);padding:2px 7px;cursor:pointer}
.as-mini:hover{color:#c0392b;border-color:#c0392b}
.as-mini-row{display:block;width:100%;margin:2px 0 8px;padding:5px 8px;text-align:center}
.as-ctname{margin-left:auto;font-size:10.5px;font-weight:800;letter-spacing:.3px;
  background:var(--as-accent-soft);color:var(--as-accent);border-radius:4px;padding:1px 6px}
.as-note{margin:2px 0 8px;font-size:10.5px;line-height:1.45;color:var(--as-mute)}
/* an unmeetable Max rows cap — say so rather than silently ignoring it */
/* a URL is long — give it the row's full width instead of the numeric column */
.as-row-wide{display:block}
.as-row-wide>label{display:block;margin-bottom:4px}
.as-row-wide>.as-f{width:100%}
.as-txtf{width:100%;box-sizing:border-box;font-size:11.5px;padding:5px 7px}
.as-note-warn{color:#b45309;background:rgba(245,158,11,.10);border-left:2px solid #f59e0b;
              padding:5px 7px;border-radius:0 4px 4px 0;margin:-2px 0 8px}
