/* Map builder — app styles (from design/mockup-figma-v2.html) */
:root{
  --ink:#1e2328; --dim:#6b7480; --faint:#9aa3ad;
  --panel:#ffffff; --canvas:#eef0f2;
  --line:#e5e8eb; --line-2:#d7dbe0;
  --hover:#f4f6f8;
  --accent:#2d7ff9; --accent-soft:rgba(45,127,249,.10); --accent-line:rgba(45,127,249,.5);
  --r:7px;
  --font:-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --topH:48px; --railW:60px; --leftW:200px; --rightW:240px;
}
*{box-sizing:border-box;margin:0;padding:0}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
body{font-family:var(--font);color:var(--ink);height:100vh;overflow:hidden;background:var(--canvas);font-size:13px}
button{font:inherit}
.ico{display:block;width:15px;height:15px;stroke:currentColor;stroke-width:1.7;fill:none;stroke-linecap:round;stroke-linejoin:round}
.ico.sm{width:13px;height:13px}
.ico.md{width:18px;height:18px}

/* ---------- top nav ---------- */
.top{position:fixed;top:0;left:0;right:0;height:var(--topH);background:var(--panel);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:4px;padding:0 12px 0 0;z-index:40}
.logo{display:flex;align-items:center;gap:8px;font-weight:700;font-size:13.5px;letter-spacing:-.01em;width:calc(var(--railW) + var(--leftW));height:100%;padding:0 12px;flex:none;color:inherit;text-decoration:none}
.logo img{width:20px;height:20px;border-radius:50%}
.betatag{font-size:9.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--dim);background:var(--hover);border:1px solid var(--line-2);border-radius:999px;padding:1px 6px}
.navfeedback{font-size:11.5px;color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.navfeedback a{color:var(--dim);text-decoration:none}
.navfeedback a:hover{color:var(--accent);text-decoration:underline}
.vsep{width:1px;height:22px;background:var(--line);margin:0 6px}
.navicon{width:32px;height:32px;border:none;background:none;border-radius:6px;color:var(--ink);display:grid;place-items:center;cursor:pointer}
.navicon:hover{background:var(--hover)}
.navicon.on{background:var(--accent-soft);color:var(--accent)}
.navicon.locked{opacity:.45}
.navicon:disabled{color:var(--line-2);cursor:default}
.navicon:disabled:hover{background:none}
.spacer{flex:1}
/* Save + Download share one width so they read as a paired action, not two
   differently-sized buttons — Save is the lower-emphasis (soft gray fill,
   no border) of the pair, Download stays the one solid/primary action. */
.savebtn{height:32px;width:96px;border-radius:6px;background:var(--hover);border:1px solid var(--line-2);color:var(--ink);font-size:13px;font-weight:600;cursor:pointer}
.savebtn:hover{background:var(--line-2)}
.navbtn.export{height:32px;width:96px;padding:0;border-radius:6px;border:none;background:var(--accent);color:#fff;font-size:13px;font-weight:600;cursor:pointer}
.navbtn.export:hover{filter:brightness(1.06)}
.acct{width:32px;height:32px;border-radius:50%;border:none;padding:0;cursor:pointer;background:linear-gradient(135deg,#2d7ff9,#7db4ff);color:#fff;display:grid;place-items:center;font-size:11px;font-weight:640}
.acct.loggedout{width:auto;height:32px;padding:0 14px;border-radius:6px;background:none;border:1px solid var(--accent-line);color:var(--accent);font-size:12.5px;font-weight:600}
.acct.loggedout:hover{background:var(--accent-soft)}

.navdrop{position:relative}
.dropmenu{position:absolute;top:36px;left:0;background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 8px 24px rgba(28,44,60,.16);padding:4px;min-width:150px;z-index:60}
.dropmenu button{display:block;width:100%;text-align:left;padding:7px 10px;border:none;background:none;border-radius:5px;cursor:pointer;font-size:12.5px}
.dropmenu button:hover{background:var(--hover)}
/* .dropmenu button's reset (0,1,1) otherwise beats .mini-btn (0,1,0) and
   silently strips its accent background/color — restore it here. */
.dropmenu button.mini-btn{background:var(--accent);color:#fff;text-align:center}
.dropmenu button.mini-btn:hover{background:var(--accent)}
.dropmenu button.on{color:var(--accent);font-weight:600}
/* Named "align-right" not "right" — a plain .right class collides with the
   #inspector panel's .right rule below (same specificity, later in source,
   so it silently won: position:fixed + bottom:0 + width:288px stretched any
   .dropmenu.right dropdown to the full viewport height). */
.dropmenu.align-right{left:auto;right:0}
.dm-section-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);padding:8px 6px 4px}

/* account menu */
.acctmenu{width:230px;max-height:75vh;overflow-y:auto;padding:10px}
.acct-form{display:flex;flex-direction:column;gap:8px}
.acct-form input{height:32px;border:1px solid var(--line-2);border-radius:6px;padding:0 10px;font:inherit;font-size:12.5px;outline:none;width:100%}
.acct-form input:focus{border-color:var(--accent-line)}
.acct-row{display:flex;gap:6px}
.acct-row .mini-btn{flex:1}
.mini-btn.ghost{background:none;color:var(--accent);border:1px solid var(--accent-line)}
.acct-google{display:flex;align-items:center;justify-content:center;gap:7px;height:32px;border:1px solid var(--line-2);border-radius:6px;background:none;font-size:12.5px;font-weight:600;cursor:pointer;width:100%}
.acct-google:hover{background:var(--hover)}
.acct-info{padding:2px 4px 8px;border-bottom:1px solid var(--line);margin-bottom:6px}
.acct-email{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-tier{font-size:11.5px;color:var(--dim);margin-top:2px}
#acct-signout,#acct-portal,#acct-plans,#acct-exports{display:block;width:100%;text-align:left;padding:7px 6px;border:none;background:none;border-radius:5px;cursor:pointer;font-size:12.5px}
#acct-signout:hover,#acct-portal:hover,#acct-plans:hover,#acct-exports:hover{background:var(--hover)}
.acct-cta{width:100%;margin-bottom:4px}
.acct-hint{padding:0 2px 8px}
.acctmenu .acct-row{margin-bottom:6px}
.acct-legal{border-top:1px solid var(--line);margin-top:6px;padding:8px 4px 2px;font-size:11px;color:var(--faint)}
.acct-legal a{color:var(--dim);text-decoration:none}
.acct-legal a:hover{text-decoration:underline}

/* ---------- icon rail ---------- */
.rail{position:fixed;top:var(--topH);left:0;bottom:0;width:var(--railW);background:var(--panel);border-right:1px solid var(--line);z-index:36;display:flex;flex-direction:column;padding:8px 0}
.railbtn{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;height:60px;border:none;background:none;color:var(--dim);cursor:pointer}
.railbtn:hover{background:var(--hover)}
.railbtn .lbl{font-size:10.5px;letter-spacing:.01em}
.railbtn.active{background:var(--accent-soft);color:var(--accent)}
.railbtn.active .lbl{font-weight:640}

/* ---------- left secondary panel ---------- */
.left{position:fixed;top:var(--topH);left:var(--railW);bottom:0;width:var(--leftW);background:var(--panel);border-right:1px solid var(--line);z-index:35;overflow:hidden}
/* Preset panel "expand" — widens over the canvas (already higher z-index)
   and switches the list to a grid so more cards are visible at once; the
   right inspector is already hidden while on the Preset tab, so nothing
   else needs to move out of the way. */
body.preset-expanded .left{width:calc(100vw - var(--railW))}
body.preset-expanded .presetlist{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));grid-auto-rows:min-content;gap:14px;align-content:start;align-items:start}
body.preset-expanded .presetcard{width:auto}
.panelbody{height:100%;display:flex;flex-direction:column}
.panelbody[hidden]{display:none}
.lhead{display:flex;align-items:center;justify-content:space-between;height:38px;padding:0 12px;border-bottom:1px solid var(--line);flex:none}
.lhead .ttl{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}

/* layers tree */
.tree{flex:1;overflow-y:auto;padding:6px}
.tree.disabled{opacity:.45;pointer-events:none}
.row{display:flex;align-items:center;gap:6px;height:30px;padding:0 8px;border-radius:6px;cursor:pointer;position:relative}
.row:hover{background:var(--hover)}
.row:hover .eye{opacity:1}
.row.sel{background:var(--accent-soft)}
.row.sel .nm{font-weight:600}
.row .chev{width:14px;height:14px;display:grid;place-items:center;color:var(--faint);flex:none}
.row .chev.leaf{visibility:hidden}
.row .sw{width:14px;height:14px;border-radius:4px;flex:none;box-shadow:inset 0 0 0 1px rgba(20,30,45,.18)}
.row .sw.cat{background:none;box-shadow:none;display:grid;place-items:center;color:var(--dim)}
.row .nm{flex:1;font-size:12.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row .eye{opacity:0;color:var(--faint);display:grid;place-items:center;width:20px;height:20px;border:none;background:none;cursor:pointer}
.row.off .nm{color:var(--faint)}
.row.off .eye{opacity:1}
.indent{width:16px;flex:none}

/* basemap type (Map / Satellite / Terrain) */
.basemaptypes{display:flex;gap:6px;padding:8px;flex:none}
.basemapcard{flex:1;padding:8px 4px;border-radius:8px;cursor:pointer;border:1px solid var(--line);background:none;text-align:center;font-size:12px;font-weight:600;color:var(--dim)}
.basemapcard:hover{background:var(--hover)}
.basemapcard.sel{background:var(--accent-soft);border-color:var(--accent-line);color:var(--accent)}

/* presets — preview tiles; tap applies */
.presetimport{display:flex;flex-direction:column;gap:6px}
.presetimport textarea{border:1px solid var(--line-2);border-radius:6px;padding:7px 9px;font:inherit;font-size:11.5px;outline:none;resize:vertical;min-height:44px;font-family:ui-monospace,Consolas,monospace}
.presetimport textarea:focus{border-color:var(--accent-line)}
.presetlist{flex:1;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:10px}
.presetlist.disabled{opacity:.45;pointer-events:none}
/* Shared "this tab is disabled on Satellite/Terrain" banner (Preset + Style
   tabs) — sits at the top of the panel, above the (dimmed) list/tree, so it
   reads as an explanation rather than a caption underneath. */
.disablednote{margin:10px 12px;padding:10px 12px;background:var(--hover);border:1px solid var(--line-2);border-radius:8px;font-size:11.5px;color:var(--dim);line-height:1.45}
/* flex-shrink:0 is the fix here — .presetlist already scrolls
   (overflow-y:auto), but a flex column's items still shrink to fit by
   default even so, so without this the cards themselves got squeezed
   (image + name row clipped) instead of the list just scrolling past them */
.presetcard{display:flex;flex-direction:column;flex-shrink:0;width:100%;padding:0;border-radius:9px;cursor:pointer;border:1.5px solid var(--line);background:var(--panel);text-align:left;overflow:hidden}
.presetcard:hover{border-color:var(--accent-line)}
.presetcard.sel{border-color:var(--accent)}
.presetcard .pp-map{width:100%;display:block;flex:none}
.presetcard .prow{display:flex;align-items:center;gap:6px;padding:6px 9px;border-top:1px solid var(--line);flex:none}
.presetcard .pname{font-size:12px;font-weight:600;line-height:1.3;flex:1;word-break:break-word}
.presetcard .check{color:var(--accent);opacity:0;display:grid;place-items:center}
.presetcard.sel .check{opacity:1}
.presetcard .pdel,.presetcard .pren{color:var(--faint);flex:none;display:grid;place-items:center;width:22px;height:22px;border-radius:5px}
.presetcard .pdel:hover{color:#d33;background:var(--hover)}
.presetcard .pren:hover{color:var(--accent);background:var(--hover)}

/* admin preset publishing block */
.admin-preset{flex:none;border-top:1px solid var(--line);padding:10px;display:flex;flex-direction:column;gap:6px}
.admin-preset[hidden]{display:none} /* display:flex would beat the hidden attr */

/* import */
.importbody{padding:14px;display:flex;flex-direction:column;gap:14px;overflow-y:auto;flex:1}
.fieldlabel{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);margin-bottom:6px}
.pasterow{display:flex;gap:6px}
.pasterow input{flex:1;height:32px;border:1px solid var(--line-2);border-radius:6px;padding:0 10px;font:inherit;font-size:12.5px;outline:none;min-width:0}
.mini-btn{height:32px;padding:0 12px;border-radius:6px;border:none;background:var(--accent);color:#fff;font-size:12.5px;font-weight:600;cursor:pointer}
.mini-btn:disabled{background:var(--line-2);cursor:default}
.hint{font-size:11.5px;color:var(--faint);line-height:1.45}
.ordiv{display:flex;align-items:center;gap:8px;color:var(--faint);font-size:11px}
.ordiv:before,.ordiv:after{content:"";flex:1;height:1px;background:var(--line)}
.dropzone{border:1.5px dashed var(--line-2);border-radius:8px;padding:22px 10px;display:flex;flex-direction:column;align-items:center;gap:8px;color:var(--faint);font-size:12px;text-align:center;cursor:pointer}
.dropzone.dragover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}

/* my maps — same card look as presets (screenshot + name + actions) */
.mymaplist{flex:1;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:10px}

/* save/rename dialog input */
.dlg-input{width:100%;height:34px;border:1px solid var(--line-2);border-radius:6px;padding:0 10px;font:inherit;font-size:13px;outline:none}
.dlg-input:focus{border-color:var(--accent-line)}

/* ---------- canvas / map ---------- */
.canvas{position:fixed;top:var(--topH);left:calc(var(--railW) + var(--leftW));right:var(--rightW);bottom:0;background:var(--canvas);z-index:10}
body.inspector-hidden .canvas{right:0}
body.inspector-floating .canvas{right:0}
body.inspector-floating .right{box-shadow:-8px 0 24px rgba(15,25,40,.18)}

/* ---------- guided export mode ---------- */
/* chrome collapses: rail + left panel + inspector gone, nav shows only the
   logo and the active export step's controls */
body.export-mode .rail,
body.export-mode .left,
body.export-mode .right{display:none}
body.export-mode .canvas{left:0;right:0}
body.export-mode .top > *:not(.logo):not(.exportnav){display:none}
.exportnav{display:flex;align-items:center;gap:10px;flex:1;min-width:0;padding:0 4px}
.exportnav[hidden]{display:none}
.exd-instr{font-size:12.5px;color:var(--dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.exd-detail-label{font-size:12px;font-weight:600;white-space:nowrap;min-width:170px}
#exd-detail-slider{width:220px}
#export-box{position:absolute;z-index:25;border:2px solid var(--accent);box-shadow:0 0 0 100000px rgba(20,30,45,.35);pointer-events:none}
/* MapLibre defaults to a grab-hand cursor at rest; features are clickable
   here, so use a pointer at rest and keep the grabbing hand only while the
   mouse is actually held down for panning. */
#map .maplibregl-canvas-container.maplibregl-interactive{cursor:pointer}
#map .maplibregl-canvas-container.maplibregl-interactive:active{cursor:grabbing}
#map{position:absolute;inset:0}
#setup-note{position:absolute;top:12px;left:50%;transform:translateX(-50%);background:#fff8e6;border:1px solid #eadfb8;color:#6e5c1e;border-radius:8px;padding:8px 14px;font-size:12px;z-index:20;max-width:80%;box-shadow:0 4px 14px rgba(28,44,60,.10)}
#setup-note code{background:rgba(0,0,0,.06);padding:1px 4px;border-radius:3px}
#measure-badge{position:absolute;left:50%;transform:translateX(-50%);bottom:18px;background:#fff;border:1px solid var(--line);border-radius:999px;padding:8px 16px;font-size:12.5px;font-weight:600;box-shadow:0 6px 20px rgba(28,44,60,.14);z-index:20}

/* ---------- bottom-right corner: privacy/terms ---------- */
.cornerbar{position:absolute;right:16px;bottom:10px;display:flex;align-items:center;gap:7px;background:rgba(255,255,255,.92);border:1px solid var(--line);border-radius:999px;padding:3px 12px;font-size:11px;color:var(--dim);z-index:20;box-shadow:0 4px 14px rgba(28,44,60,.08)}
.cornerbar a{color:var(--dim);text-decoration:none}
.cornerbar a:hover{color:var(--ink);text-decoration:underline}
.cornerbar .sep{color:var(--faint)}

/* ---------- support banner (free tier only, js/ads.js) ---------- */
.supportbanner{position:absolute;left:50%;bottom:18px;transform:translateX(-50%);display:flex;align-items:center;gap:16px;background:#fff;border:1px solid var(--line);border-radius:16px;padding:14px 14px 14px 22px;box-shadow:0 10px 30px rgba(28,44,60,.16);z-index:20;font-size:12.5px;max-width:min(90vw,620px)}
.supportbanner[hidden]{display:none} /* display:flex would beat the hidden attr */
.supportbanner span{color:var(--ink)}
.supportbanner .mini-btn{flex:none;white-space:nowrap}
.supportbanner-close{width:22px;height:22px;border:none;background:var(--hover);border-radius:50%;cursor:pointer;color:var(--dim);display:grid;place-items:center;flex:none}
.supportbanner-close:hover{background:var(--line-2)}
/* ---------- floating map toolbar: Search / Map style / Measure / Zoom ---------- */
/* Search is a permanent expanded bar (not a toggle) — Map style/Zoom instead
   expand THIS pill in place (icons swap out for that tool's own row) rather
   than opening a second floating box below it. Only one of .maptools-icons /
   #menu-mapstyle / #menu-detail is ever visible at a time, alongside the
   always-visible search bar, so the pill's width just follows whatever's
   currently showing. */
.maptools{position:absolute;top:12px;left:12px;display:flex;align-items:center;gap:1px;background:#fff;border:1px solid var(--line);border-radius:9px;padding:3px;box-shadow:0 8px 24px rgba(28,44,60,.16);z-index:26}
.maptools .navicon{border-radius:6px}
.maptools .divider{width:1px;height:18px;background:var(--line-2);margin:0 3px}

/* the permanently-expanded search bar — Map style/Zoom are plain dropdowns
   (.navdrop/.dropmenu below), not part of this */
.maptools-panel{display:flex;align-items:center;gap:8px;height:32px;padding:0 4px 0 8px;color:var(--dim);position:relative}
.maptools-panel.locked{opacity:.45}
.maptools-panel #search-input{flex:1;min-width:200px;border:none;outline:none;font:inherit;font-size:13px;color:var(--ink)}
.search-clear{border:none;background:none;color:var(--faint);cursor:pointer;display:grid;place-items:center;width:22px;height:22px;flex:none;border-radius:5px}
.search-clear:hover{background:var(--hover);color:var(--ink)}

/* Level-of-detail dropdown (below the zoom icon) */
.detailpop{width:200px;padding:12px;display:flex;flex-direction:column;gap:8px}
/* .detailpop's own `display:flex` otherwise ties with (and as an author rule,
   beats) the browser's default [hidden]{display:none} — needs restating here */
.detailpop[hidden]{display:none}
.detailpop input[type=range]{width:100%}
.detail-label{font-size:12px;color:var(--dim);text-align:center}

/* anchored to #searchbox itself so it stays under just the search bar's own width */
.searchresults{position:absolute;top:38px;left:0;right:0;background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 8px 24px rgba(28,44,60,.16);overflow:hidden}
.searchresults button{display:block;width:100%;text-align:left;border:none;background:none;padding:9px 12px;cursor:pointer;font-size:12.5px}
.searchresults button:hover{background:var(--hover)}
.searchresults .sub{display:block;font-size:11px;color:var(--faint)}

/* ---------- right inspector ---------- */
.right{position:fixed;top:var(--topH);right:0;bottom:0;width:var(--rightW);background:var(--panel);border-left:1px solid var(--line);z-index:35;display:flex;flex-direction:column;overflow-y:auto}
.right[hidden]{display:none}
.insp-head{padding:14px 16px 12px;border-bottom:1px solid var(--line)}
.insp-head .crumb{font-size:11px;color:var(--faint);margin-bottom:3px}
.insp-head .title{font-size:15px;font-weight:680;letter-spacing:-.01em}
.section{border-bottom:1px solid var(--line);padding:14px 16px}
.sec-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.sec-top .st{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dim)}
.sec-top .toggle{width:22px;height:22px;border-radius:5px;border:none;background:none;color:var(--ink);cursor:pointer;display:grid;place-items:center}
.sec-top .toggle:hover{background:var(--hover)}
.section.off{opacity:.55}
.section.off .toggle{color:var(--faint)}
.prop{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.prop:last-child{margin-bottom:0}
.prop .plabel{width:44px;font-size:12px;color:var(--dim)}
/* Fill/Stroke rows specifically: force the label to a true fixed width —
   plain `width` on a flex item is only a hint (a single unbreakable word
   like "Stroke" can still report a larger min-content size and win), which
   was throwing off the colorfield + propeye position after it, row to row */
.propcolor .plabel{flex:none;overflow:hidden;white-space:nowrap}
.colorfield{flex:1;min-width:0;display:flex;align-items:center;gap:6px;height:32px;border:1px solid var(--line-2);border-radius:6px;padding:0 6px;background:#fff;position:relative}
/* being itself a flex container, .colorfield's default min-width:auto pins
   it to its own content's min size, ignoring `flex:1` — that was pushing the
   whole row (and the propeye after it) past the section's right edge */
/* property hidden (eye toggled off) — stays in place (so the box + the
   .propeye after it never shift position) but reads as disabled */
.colorfield.off{opacity:.5;background:var(--hover)}
.colorfield.off .chip,.colorfield.off input{cursor:not-allowed}
/* same lighter --faint the disabled Width slider's "Width" title uses (see
   .prop-disabled .plabel below) — a hidden Fill/Stroke row's own title
   should read just as de-emphasized, not stay full-strength while only the
   swatch/eye next to it dim. */
.prop.off .plabel{color:var(--faint)}
/* native select arrow sits flush against the box's right edge regardless of
   padding in Chromium — appearance:none + a hand-drawn chevron is the only
   way to actually control its inset */
.prop select.dlg-input{flex:1;width:auto;height:32px;appearance:none;-webkit-appearance:none;padding-right:30px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7480' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;background-size:14px}
.colorfield .chip{width:16px;height:16px;border-radius:4px;box-shadow:inset 0 0 0 1px rgba(20,30,45,.16);flex:none;cursor:pointer;border:none;padding:0}
.colorfield .chip:disabled{cursor:not-allowed}
.colorfield .hex{font-size:11.5px;font-variant-numeric:tabular-nums;flex:1;border:none;outline:none;background:none;font-family:inherit;min-width:0;text-transform:uppercase}
.propeye{width:22px;height:22px;flex:none;border-radius:5px;border:none;background:none;color:var(--ink);cursor:pointer;display:grid;place-items:center}
.propeye:hover{background:var(--hover)}
.propeye.off{color:var(--faint)}
/* fixed-width trailing column, shared with .rv (the Opacity/Width readout)
   below — this is what actually makes .colorfield and the slider render
   the same width: both rows reserve the identical trailing-column width,
   so their flex:1 control gets the identical remaining space. The icon
   itself stays a normal 22px square button, right-aligned within the
   wider column rather than stretched to fill it. */
.propaccessory{width:36px;flex:none;display:flex;justify-content:flex-end;align-items:center}
.insp-empty{padding:20px 16px;color:var(--faint);font-size:12.5px;line-height:1.5}

/* ---------- shared color picker popover (js/colorpicker.js) ---------- */
.cpicker{position:fixed;z-index:200;width:232px;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 12px 40px rgba(15,25,40,.25);padding:12px}
.cpicker[hidden]{display:none}
.cp-sl{position:relative;width:100%;height:140px;border-radius:6px;cursor:crosshair;margin-bottom:10px;user-select:none}
.cp-sl-dot{position:absolute;width:14px;height:14px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.4),0 1px 4px rgba(0,0,0,.3);transform:translate(-50%,-50%);pointer-events:none}
.cp-controls{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.cp-eyedrop{width:28px;height:28px;flex:none;border:none;background:none;border-radius:6px;color:var(--dim);cursor:pointer;display:grid;place-items:center}
.cp-eyedrop:hover{background:var(--hover)}
.cp-eyedrop[hidden]{display:none}
.cp-sliders{flex:1;display:flex;flex-direction:column;gap:10px;min-width:0}
.cp-hue{position:relative;height:12px;border-radius:999px;cursor:pointer;user-select:none}
.cp-hue{background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}
.cp-slider-dot{position:absolute;top:50%;width:14px;height:14px;border-radius:50%;background:#fff;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.4),0 1px 4px rgba(0,0,0,.3);transform:translate(-50%,-50%);pointer-events:none}
.cp-fields{display:flex;gap:8px}
/* format picker (Hex/RGB/HSL) — same appearance:none + hand-drawn-chevron
   treatment as .prop select.dlg-input, just sized for the 232px popover */
.cp-format{flex:none;width:62px;height:30px;border:1px solid var(--line-2);border-radius:6px;padding:0 18px 0 8px;font:inherit;font-size:12px;color:var(--ink);background-color:#fff;appearance:none;-webkit-appearance:none;cursor:pointer;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7480' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 5px center;background-size:12px}
/* Hex is a single free-text field (unchanged from before); RGB/HSL instead
   render 3 short per-channel fields side by side, divided by hairlines, so
   switching format swaps what's inside the same box rather than changing
   its shape. */
.cp-valuefield{flex:1;display:flex;align-items:center;height:30px;border:1px solid var(--line-2);border-radius:6px;min-width:0;overflow:hidden}
.cp-valuefield input{flex:1;width:0;min-width:0;border:none;outline:none;font-size:12.5px;font-family:inherit;height:100%;background:none;text-align:center;padding:0 2px}
.cp-valuefield.cp-hexmode input{text-align:left;padding:0 8px;text-transform:uppercase}
.cp-valuefield:not(.cp-hexmode) input:not(:first-child){border-left:1px solid var(--line-2)}

/* ---------- export dialog ---------- */
.dialog-scrim{position:fixed;inset:0;background:rgba(20,28,38,.35);z-index:80;display:grid;place-items:center}
.dialog-scrim[hidden]{display:none}
.dialog{width:430px;max-width:94vw;background:#fff;border-radius:12px;box-shadow:0 20px 60px rgba(15,25,40,.3);overflow:hidden}
.dlg-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--line);font-weight:680;font-size:14px}
.dlg-close{width:28px;height:28px;border:none;background:none;display:grid;place-items:center;cursor:pointer;color:var(--dim);border-radius:6px}
.dlg-close:hover{background:var(--hover)}
.dlg-body{padding:16px}
.dlg-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 16px;border-top:1px solid var(--line)}
/* wide enough that "Download PNG"/"Download SVG" never wraps to 2 lines;
   margin-left:auto keeps it pinned right now that the attribution hint
   that used to share this footer is gone */
#export-go{min-width:170px;white-space:nowrap;flex:none;margin-left:auto}
.dialog.wide{width:640px}
.codetabs{display:flex;gap:4px;padding:12px 16px 0}
.codetab{height:30px;padding:0 12px;border-radius:6px;border:none;background:none;color:var(--dim);font-size:12.5px;font-weight:600;cursor:pointer}
.codetab:hover{background:var(--hover)}
.codetab.sel{background:var(--accent-soft);color:var(--accent)}
.code-body{padding-top:10px}
.codeblock{font-family:ui-monospace,Consolas,monospace;font-size:11.5px;line-height:1.5;white-space:pre;overflow:auto;max-height:52vh;background:var(--canvas);border:1px solid var(--line);border-radius:6px;padding:12px}
.sizegrid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.sizecard{border:1px solid var(--line-2);border-radius:8px;padding:10px 12px;cursor:pointer;background:none;text-align:left;position:relative}
.sizecard:hover{border-color:var(--accent-line)}
.sizecard.sel{border-color:var(--accent);background:var(--accent-soft)}
.sizecard .sz{font-weight:650;font-size:13px}
.sizecard .sub{font-size:11px;color:var(--faint);margin-top:2px}
.sizecard .price{position:absolute;top:9px;right:10px;font-size:11px;font-weight:700;color:var(--accent)}
.sizecard.locked{opacity:.6;cursor:default}
.sizecard.locked .price{color:var(--faint)}
.sizecard.warned .sub{color:#b8860b}
.rec-badge{font-size:9.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#0a7d38;background:rgba(16,163,74,.12);border-radius:4px;padding:1px 5px;margin-left:4px;vertical-align:2px}
.detailrow{display:flex;gap:4px}
.seg{height:28px;padding:0 12px;border:1px solid var(--line-2);background:none;border-radius:999px;font-size:12px;color:var(--dim);cursor:pointer}
.seg.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.coverage{margin-top:10px;font-size:11.5px;color:var(--faint)}
.exp-note{margin-top:10px;font-size:11.5px;color:var(--dim);line-height:1.5}
.exp-note b{color:var(--ink)}

/* my exports dialog */
.exportlist{display:flex;flex-direction:column;gap:6px;max-height:60vh;overflow-y:auto}
.exportrow{display:flex;align-items:center;gap:10px;padding:9px 10px;border:1px solid var(--line-2);border-radius:8px}
.exportrow .ex-info{flex:1;min-width:0}
.exportrow .ex-dim{font-weight:650;font-size:12.5px}
.exportrow .ex-meta{display:block;font-size:11px;color:var(--faint);margin-top:2px}
.exportrow.s-expired,.exportrow.s-failed,.exportrow.s-stale{opacity:.7}
.ex-state{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--dim)}
.ex-state.ex-bad{color:#b3261e}
.ex-dl{height:28px;padding:0 12px}
.acct-badge{font-size:9.5px;font-weight:700;color:var(--accent);vertical-align:1px}
.spin{width:12px;height:12px;border-radius:50%;border:2px solid var(--line-2);border-top-color:var(--accent);display:inline-block;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* toast */
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--ink);color:#fff;border-radius:8px;padding:10px 18px;font-size:12.5px;z-index:100;box-shadow:0 8px 24px rgba(0,0,0,.25)}

/* maplibre chrome adjustments */
.maplibregl-ctrl-bottom-left{z-index:15}
.maplibregl-ctrl-attrib{font-size:10.5px}

/* ===== overlay editor (2026-07-06) ===== */
.lhead .headbtn{width:24px;height:24px;border:none;background:none;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--dim);padding:0}
.lhead .headbtn:hover{background:var(--hover);color:var(--accent)}
/* #btn-language shows the current language's code (e.g. "EN") once one is
   picked, in place of the generic languages icon. A resting background
   (unlike the other plain .headbtn icons) marks it as its own tappable
   control, since text alone next to a section title could read as a label. */
#btn-language{font:700 9.5px/1 var(--font);letter-spacing:-.02em;width:auto;min-width:24px;padding:0 6px;background:var(--hover)}
#btn-language:hover{background:var(--accent-soft);color:var(--accent)}
#overlay-add-menu{top:28px}
#overlay-add-menu button{display:flex;align-items:center;gap:8px}
.ovlist{flex:1;overflow-y:auto;padding:8px}
.ovrow{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:7px;cursor:pointer;font-size:12.5px}
.ovrow:hover{background:var(--hover)}
.ovrow.sel{background:var(--accent-soft);color:var(--accent)}
.ovrow.drawing{color:var(--dim);font-style:italic;cursor:default}
.ovrow .ovic{color:var(--dim);display:flex;flex:none}
.ovrow.sel .ovic{color:var(--accent)}
.ovrow .ovname{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ovrow .ovbtn{border:none;background:none;cursor:pointer;color:var(--faint);padding:2px;display:none;flex:none}
.ovrow:hover .ovbtn{display:flex}
.ovrow .ovbtn:hover{color:var(--accent)}
.ovrow input.ovedit{flex:1;font-size:12.5px;padding:3px 6px;border:1px solid var(--accent);border-radius:5px;min-width:0;font-family:inherit;outline:none}
.ovempty{padding:14px 12px;font-size:12px;color:var(--faint);line-height:1.5}
.rangefield{flex:1;height:32px;display:flex;align-items:center;gap:8px;min-width:0}
.rangefield input[type=range]{flex:1;min-width:0}
/* Overlay-tab's own rangeRow (Weight/Sides/Rotation/Size) still nests its
   readout inside .rangefield, so this descendant rule keeps styling it. */
.rangefield .rv{font-size:11.5px;color:var(--dim);font-variant-numeric:tabular-nums;width:38px;text-align:right;flex:none}
/* Layers-tab Opacity/Width rows (js/ui.js) instead render .rv as a sibling
   of .rangefield, not nested inside it — same fixed-width-trailing-column
   trick as .propaccessory above, so input[type=range] — the part that
   actually reads as "the slider" — renders the exact same width as
   .colorfield, and the two trailing columns (the eye icon, the %/px
   readout) land flush on the same right edge across every row. */
.rv{font-size:11.5px;color:var(--dim);font-variant-numeric:tabular-nums;width:36px;text-align:right;flex:none}

/* ---------- range sliders (shared: Layers/Overlay dimension + Opacity knobs,
   top-nav detail-zoom, export-flow detail-zoom) — a plain accent-colored
   native thumb sits on an accent-colored filled track and visually vanishes
   into it, so both are re-skinned: filled portion in --accent, thumb a white
   disc with an --accent ring (same look as the color picker's own hue/SL
   dots) so it reads as a distinct handle at any position. --pct (0-100%,
   set from JS on render + on input) draws the fill boundary. */
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:16px;margin:0;background:none;cursor:pointer}
input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:999px;background:linear-gradient(to right,var(--accent) 0 var(--pct,0%),var(--line-2) var(--pct,0%) 100%)}
input[type=range]::-moz-range-track{height:4px;border-radius:999px;background:var(--line-2)}
input[type=range]::-moz-range-progress{height:4px;border-radius:999px 0 0 999px;background:var(--accent)}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;box-sizing:border-box;margin-top:-6px;width:16px;height:16px;border-radius:50%;background:#fff;border:2px solid var(--accent);box-shadow:0 1px 3px rgba(15,25,40,.35)}
input[type=range]::-moz-range-thumb{box-sizing:border-box;width:16px;height:16px;border-radius:50%;background:#fff;border:2px solid var(--accent);box-shadow:0 1px 3px rgba(15,25,40,.35)}

/* Property panel's Opacity and Width sliders re-skin the shared range
   control in --faint instead of --accent — neither is a selection control
   (Opacity's a transparency knob, Width's a stroke-thickness knob), so
   neither should read as an active/interactive accent color. */
.prop-opacity input[type=range]::-webkit-slider-runnable-track,.prop-width input[type=range]::-webkit-slider-runnable-track{background:linear-gradient(to right,var(--faint) 0 var(--pct,0%),var(--line-2) var(--pct,0%) 100%)}
.prop-opacity input[type=range]::-moz-range-progress,.prop-width input[type=range]::-moz-range-progress{background:var(--faint)}
.prop-opacity input[type=range]::-webkit-slider-thumb,.prop-width input[type=range]::-webkit-slider-thumb{border-color:var(--faint)}
.prop-opacity input[type=range]::-moz-range-thumb,.prop-width input[type=range]::-moz-range-thumb{border-color:var(--faint)}

/* Buildings' Stroke width when Render isn't "Outline" — inert but tappable
   (see js/ui.js widthProp's disabledReason): the slider itself gets
   pointer-events:none so dragging/clicking it does nothing, while a
   transparent overlay sibling sits on top and catches the tap to explain
   why via toast. A real `disabled` attribute would swallow that tap
   silently instead. Visually it stays the same regular slider look (same
   track/thumb, no opacity wash) just recolored a step lighter than the
   already-light --faint regular slider — --line-2/--line instead — and its
   label/readout drop to --faint, so "disabled" reads as a lighter color
   rather than a translucent film over the same one. */
.prop-disabled .rangefield{position:relative}
.prop-disabled .rangefield input[type=range]{pointer-events:none}
.prop-disabled .plabel{color:var(--faint)}
.prop-disabled .rv{color:var(--faint)}
.prop-disabled input[type=range]::-webkit-slider-runnable-track{background:linear-gradient(to right,var(--line-2) 0 var(--pct,0%),var(--line) var(--pct,0%) 100%)}
.prop-disabled input[type=range]::-moz-range-track{background:var(--line)}
.prop-disabled input[type=range]::-moz-range-progress{background:var(--line-2)}
.prop-disabled input[type=range]::-webkit-slider-thumb{border-color:var(--line-2)}
.prop-disabled input[type=range]::-moz-range-thumb{border-color:var(--line-2)}
.width-disabled-overlay{position:absolute;inset:0;background:none;border:none;padding:0;margin:0;cursor:not-allowed}
.insp-hint{padding:12px 16px;font-size:11.5px;color:var(--faint);line-height:1.5}

/* marker icon picker (overlay inspector) */
.prop.iconprop{align-items:flex-start}
.prop.iconprop .plabel{padding-top:5px}
.iconpick{flex:1;display:grid;grid-template-columns:repeat(5,1fr);gap:4px}
.iconpick .ipbtn{height:28px;border:1px solid var(--line-2);border-radius:6px;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--dim);padding:0}
.iconpick .ipbtn:hover{border-color:var(--accent-line);color:var(--accent)}
.iconpick .ipbtn.on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.iconpick .ipbtn svg{width:16px;height:16px}
.iconpick .ipdot{width:12px;height:12px;border-radius:50%;background:currentColor;box-shadow:0 0 0 2px #fff,0 0 0 3px currentColor}
