:root{
  /* 1.4.3 Contrast — #1d8296 is only ~3.9:1 on white; #16697b clears 4.5:1
     (matches this file's own hardcoded AA overrides below) so the no-config
     default passes without relying on the JS clamp. */
  --teal:#16697b;
  --teal-dark:#16697b;
  --ink:#1f2523;
  --muted:#67706b;
  --line:#d8e0dd;
  --card:#ffffff;
  --soft:#f5f8f7;
  --shadow:0 10px 28px rgba(15,30,34,.18);
  /* Brand-badge geometry (top-right). Single-sourced here so the desktop
     clearance for the search bar + hint derives from the badge — change the
     badge width once and the layout that dodges it follows. */
  --badge-w:112px;
  --badge-edge:16px;
  --badge-gap:36px;
  --shell-clear:calc(var(--badge-edge) + var(--badge-w) + var(--badge-gap));
}
*{box-sizing:border-box}
html,body{height:100%;margin:0;overflow:hidden}
body{font-family:Sora,system-ui,-apple-system,Segoe UI,sans-serif;background:#dceee8;color:var(--ink)}
button,input{font:inherit}
button{-webkit-tap-highlight-color:transparent}
#map{position:fixed;inset:0;z-index:1}
.overlay{position:fixed;inset:0;background:rgba(20,31,34,.24);z-index:790;opacity:0;pointer-events:none;transition:opacity .2s ease}
.overlay.show{opacity:1;pointer-events:auto}
.search-shell{position:fixed;top:calc(14px + env(safe-area-inset-top));left:16px;right:var(--shell-clear);z-index:820;display:flex;gap:12px;align-items:flex-start;pointer-events:none}
.search-wrap{width:min(420px,100%);pointer-events:auto;position:relative}
.search-bar{height:56px;background:#fff;border:1px solid rgba(216,224,221,.95);border-radius:28px;box-shadow:0 4px 18px rgba(0,0,0,.18);display:flex;align-items:center;gap:6px;padding:0 8px}
.icon-btn{border:0;background:transparent;width:42px;height:42px;border-radius:50%;display:grid;place-items:center;color:#424946;cursor:pointer;flex:0 0 auto}
.icon-btn:hover{background:#f1f4f3}
.icon-btn svg{width:23px;height:23px;fill:none;stroke:currentColor;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round}
.search-input{flex:1;min-width:0;border:0;outline:0;font-size:15px;font-weight:400;color:var(--ink);padding:0 4px;background:transparent}
.search-input::placeholder{color:#58615c;opacity:.92}
.search-submit{color:var(--teal)}
.search-avatar{width:38px;height:38px;border-radius:50%;background:linear-gradient(135deg,#1d8296,#66b6c4);color:#fff;font-weight:900;font-size:14px;letter-spacing:-.04em;display:none;place-items:center;flex:0 0 auto;text-decoration:none;border:2px solid rgba(255,255,255,.35);margin-right:3px}
.lang-btn{font-size:10px;font-weight:900;letter-spacing:.07em;color:var(--teal-dark);min-width:36px}
/* SC 2.4.7 — the picker sits inside position:fixed chrome in a document that
   cannot scroll (html,body{overflow:hidden}) and the embed iframe is a fixed
   600px, so without its own scroll container every option past ~the 12th was
   simply off the embed: a district serving many home languages shipped a menu
   whose bottom half no parent could reach, by keyboard or by touch. */
.lang-picker{position:absolute;top:calc(100% + 6px);right:0;background:#fff;border:1px solid var(--line);border-radius:16px;box-shadow:0 4px 18px rgba(0,0,0,.16);overflow:hidden;overflow-y:auto;max-height:min(60vh,320px);overscroll-behavior:contain;z-index:900;min-width:148px}
.lang-opt{display:block;width:100%;text-align:start;padding:12px 18px;font-size:13px;font-weight:600;background:none;border:none;border-bottom:1px solid var(--line);cursor:pointer;color:var(--ink)}
.lang-opt:last-child{border-bottom:none}
.lang-opt:hover{background:#f7fbfa}
.lang-opt.active{color:var(--teal);font-weight:800}

.brand-badge{position:fixed;top:calc(14px + env(safe-area-inset-top));right:var(--badge-edge);z-index:830;width:var(--badge-w);height:56px;padding:0 10px;border:1px solid rgba(216,224,221,.95);border-radius:28px;background:rgba(255,255,255,.96);box-shadow:0 4px 18px rgba(0,0,0,.16);display:flex;align-items:center;justify-content:center;text-decoration:none;color:var(--ink);backdrop-filter:blur(8px);pointer-events:auto}
.brand-badge:hover{opacity:.85}
.brand-mark{width:36px;height:36px;border-radius:12px;background:linear-gradient(135deg,#1d8296,#66b6c4);display:grid;place-items:center;color:#fff;font-weight:900;font-size:13px;letter-spacing:-.04em;box-shadow:inset 0 0 0 2px rgba(255,255,255,.26)}
/* has-logo: override the glyph's display:grid (which, with the percentage-sized
   img, blew the logo up to its intrinsic size and overflowed the badge) and pin
   the logo to a fixed square that frames a full-bleed crest cleanly. */
.brand-mark.has-logo{display:block;width:auto;height:40px;max-width:150px;background:transparent;box-shadow:none;border-radius:10px;padding:0}
/* District logos are NOT square. Klein's is a 250x71 wordmark, and forcing it
   into a 40x40 box with object-fit:contain scaled it to 40x11 — a sliver that
   read as an empty badge. Fix the HEIGHT and let the width follow the aspect
   ratio, capped so a very wide logo can't run off the map. */
.brand-mark.has-logo .brand-logo{width:auto;height:40px;max-width:150px;border-radius:10px;object-fit:contain}
.brand-logo{width:36px;height:36px;border-radius:10px;object-fit:contain}
/* A logo badge shrinks to a tidy square framing the logo, instead of a wide pill
   with a small logo lost in it. (Falls back to the pill where :has is unsupported.) */
.brand-badge:has(.brand-mark.has-logo){width:auto;min-width:56px;max-width:calc(100vw - 2*var(--badge-edge));padding:0 8px;border-radius:16px}
.drop{display:none;margin-top:8px;background:#fff;border:1px solid var(--line);border-radius:18px;overflow:auto;max-height:min(48dvh,300px);box-shadow:var(--shadow)}
.drop-item{padding:12px 14px;border-bottom:1px solid #edf1ef;font-size:13px;line-height:1.4;cursor:pointer}
.drop-item:last-child{border-bottom:0}
.drop-item:hover{background:#f7fbfa}
.drop-item.muted{color:var(--muted);cursor:default}
.pill-strip{pointer-events:auto;flex:1;display:flex;gap:9px;overflow-x:auto;padding:0 4px;scrollbar-width:none}
.pill-strip::-webkit-scrollbar{display:none}
.pill{height:36px;white-space:nowrap;border:1px solid #d5dedb;background:#fff;color:#232a28;border-radius:18px;padding:0 14px;display:inline-flex;align-items:center;font-size:12px;font-weight:700;box-shadow:0 2px 8px rgba(0,0,0,.10);cursor:pointer;touch-action:manipulation}
.pill:hover{background:#f7fbfa}
.pill.active{border-color:var(--teal);color:var(--teal);box-shadow:0 0 0 3px rgba(29,130,150,.16), 0 2px 9px rgba(0,0,0,.13)}
@media (min-width:901px){.hint{top:calc(82px + env(safe-area-inset-top))}.search-shell{align-items:center}}

.hint{position:fixed;top:calc(82px + env(safe-area-inset-top));left:16px;right:var(--shell-clear);max-width:420px;z-index:760;background:rgba(255,255,255,.96);border:1px solid var(--line);border-radius:18px;box-shadow:0 7px 24px rgba(0,0,0,.16);padding:12px 42px 12px 14px;font-size:12px;line-height:1.45;color:var(--muted);backdrop-filter:blur(8px)}
.hint strong{display:block;color:var(--ink);margin-bottom:2px}
/* Was the text glyph × (font-size:20px); now a stroked SVG matching
   .close-btn svg (the panel's own close button) instead of a second, text-
   glyph close icon elsewhere in the same widget. */
.hint button{position:absolute;right:8px;top:8px;width:28px;height:28px;border:0;border-radius:50%;background:#edf2f0;color:#59635f;display:grid;place-items:center;cursor:pointer}
.hint button svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2.3;stroke-linecap:round;stroke-linejoin:round}
.hint.hidden{display:none}
/* visibility (not just the off-screen transform) is what actually takes the
   closed panel out of the tab order and the accessibility tree — the JS sets
   `inert` too, this is the fallback where inert is unsupported. It flips only
   after the slide-out finishes so the close animation still plays. */
.side-panel{position:fixed;left:0;top:0;bottom:0;width:min(390px,92vw);background:#fff;z-index:900;transform:translateX(-103%);visibility:hidden;transition:transform .22s ease,visibility 0s linear .22s;box-shadow:14px 0 36px rgba(0,0,0,.22);display:flex;flex-direction:column;border-right:1px solid var(--line)}
.side-panel.open{transform:translateX(0);visibility:visible;transition:transform .22s ease,visibility 0s}
.panel-head{padding:18px 18px 12px;display:flex;align-items:flex-start;gap:12px;border-bottom:1px solid var(--line)}
.panel-head-text{flex:1;min-width:0}
.panel-kicker{font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--teal);margin-bottom:5px}
.panel-title{font-size:22px;font-weight:800;letter-spacing:-.04em;line-height:1.05;margin:0}
.panel-subtitle{margin-top:6px;font-size:12px;color:var(--muted);line-height:1.45}
.close-btn,.back-btn{border:0;background:#eff4f2;color:#58615c;width:38px;height:38px;border-radius:50%;display:grid;place-items:center;cursor:pointer;flex:0 0 auto}
.close-btn:hover,.back-btn:hover{background:#e7eeeb;color:#1f2523}
.back-btn[hidden]{display:none}
.close-btn svg,.back-btn svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2.3;stroke-linecap:round;stroke-linejoin:round}
.panel-body{padding:16px 18px calc(24px + env(safe-area-inset-bottom));overflow:auto}
.panel-desc{margin:0 0 14px;font-size:13px;color:var(--muted);line-height:1.5}
.panel-body::-webkit-scrollbar{width:6px}
.panel-body::-webkit-scrollbar-thumb{background:#d2dad7;border-radius:999px}
.status{display:inline-flex;align-items:center;gap:7px;padding:6px 10px;border-radius:999px;background:#eaf6f8;color:var(--teal);font-size:11px;font-weight:800;margin-bottom:10px}
.status.out{background:#fff4e7;color:#a55d00}
.card{background:linear-gradient(180deg,#fff,#fbfdfc);border:1px solid var(--line);border-radius:18px;padding:14px;margin-bottom:12px}
.card h3{margin:0 0 6px;font-size:15px;letter-spacing:-.02em}
.card p{margin:0;color:var(--muted);font-size:12px;line-height:1.5}
.pathway{display:grid;gap:10px;margin:14px 0}
.tea-badge{display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:800;padding:2px 6px;border-radius:6px;background:#edf4f2;color:#16697b;white-space:nowrap}
.tea-badge.unverified{background:#f5f0e8;color:#8a6300}
.tea-badge.nearest{background:#eaf6f8;color:#16697b}
/* .grade used to drop to 9px — this badge is the zone/pathway ANSWER, the one
   string a parent opens the widget to read (SC 1.4.4 Resize text / the 12px
   floor this file otherwise holds everywhere else); the grade letter now
   inherits .tea-badge's size instead of shrinking further. */
/* text-align:start (not left): these are <button>s, so the declaration only
   exists to beat the UA's centering — pinning it to the physical left jammed
   Arabic/Urdu result cards against the wrong edge. Identical in LTR. */
.path-card{position:relative;border:1px solid var(--line);border-radius:18px;padding:13px;background:linear-gradient(180deg,#fff,#fbfdfc);cursor:pointer;text-align:start;width:100%;touch-action:manipulation}
/* Stretched link: the whole card opens the campus, but the card stays a
   plain <div>. Wrapping it in a button instead would nest the
   Call/Directions/Enroll links inside a button — invalid HTML and axe's
   nested-interactive violation (the same bug fixed in schooldirectory.js),
   and it would swallow their accessible names into one giant label.
   Here the single 'View campus' button keeps its own name and keyboard
   behaviour; only its HIT AREA grows. */
.path-card .mini-link[data-school-name]::after{content:'';position:absolute;inset:0;border-radius:inherit}
/* Raise the real links above that overlay so they stay clickable. */
.path-card .mini-actions a.mini-link{position:relative;z-index:1}
/* Keep the focus ring on the button itself, not the stretched area. */
.path-card .mini-link[data-school-name]{position:static}
.path-card:hover,.school-row:hover{border-color:rgba(29,130,150,.45);box-shadow:0 5px 18px rgba(0,0,0,.06)}
.path-top{display:flex;gap:11px;align-items:flex-start}
.path-icon{width:38px;height:38px;border-radius:13px;color:#fff;font-weight:900;display:grid;place-items:center;flex:0 0 auto}
.path-card h4{margin:0;font-size:14px;letter-spacing:-.02em}
.path-card p{margin:4px 0 0;color:var(--muted);font-size:12px;line-height:1.5}
.mini-actions,.actions{display:grid;gap:8px}
.mini-actions{grid-template-columns:repeat(3,1fr);margin-top:10px}
.actions{grid-template-columns:repeat(2,1fr);margin:14px 0}
.btn,.mini-link{border:0;border-radius:13px;text-decoration:none;display:inline-flex;justify-content:center;align-items:center;gap:6px;font-weight:800;cursor:pointer;touch-action:manipulation}
.btn{background:var(--teal);color:#fff;font-size:12px;padding:11px 12px}
.btn:hover{background:var(--teal-dark)}
.btn.secondary{background:#eef7f8;color:var(--teal);border:1px solid rgba(29,130,150,.22)}
.btn.light{background:#fff;color:var(--teal);border:1px solid var(--line)}
.mini-link{background:#f2f7f7;color:var(--teal);border:1px solid rgba(29,130,150,.18);font-size:12px;padding:8px 6px}


.link-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:10px 0 14px}
.resource-link{background:#fff;border:1px solid var(--line);border-radius:14px;padding:10px;text-decoration:none;color:var(--ink);display:grid;gap:2px;min-height:58px}
.resource-link:hover{border-color:rgba(29,130,150,.45);box-shadow:0 5px 18px rgba(0,0,0,.06)}
.resource-link strong{font-size:12px;line-height:1.25}
.resource-link span{font-size:12px;color:var(--muted);line-height:1.4;font-weight:700}
.section-title{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:4px 0 10px}
.section-title h3{margin:0;font-size:14px;letter-spacing:-.02em}
.section-title span{font-size:11px;color:var(--muted)}
.school-list{display:grid;gap:8px}
.school-row{border:1px solid var(--line);border-radius:16px;background:#fff;padding:11px 12px;display:flex;gap:11px;align-items:flex-start;cursor:pointer;text-align:start;width:100%;touch-action:manipulation}
.school-dot{width:32px;height:32px;border-radius:11px;color:#fff;font-size:13px;font-weight:900;display:grid;place-items:center;flex:0 0 auto}
.school-meta{flex:1;min-width:0}
.school-name{font-size:13px;font-weight:800;line-height:1.3}
.school-sub{font-size:12px;color:var(--muted);margin-top:3px;line-height:1.4}
/* Was the text glyph › (font-size:18px); now a stroked SVG, matching the
   panel's own back-chevron (.back-btn svg) instead of one glyph strategy here
   and another there. */
.school-arrow{color:#9aa5a1}
.school-arrow svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,20px);z-index:980;background:rgba(33,38,36,.94);color:#fff;padding:11px 14px;border-radius:14px;font-size:12px;font-weight:700;opacity:0;pointer-events:none;transition:.2s ease}
.toast.show{opacity:1;transform:translate(-50%,0)}
.center-crosshair{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:730;pointer-events:none;opacity:.35;transition:opacity .25s ease}
.center-crosshair.moving{opacity:.7}
.center-crosshair svg{display:block;width:34px;height:34px;fill:none;stroke:#222a27;stroke-width:1.5;stroke-linecap:round;filter:drop-shadow(0 0 1.5px rgba(255,255,255,.95))}
.center-crosshair .ch-dot{fill:#222a27;stroke:none}
.map-controls{position:fixed;right:18px;bottom:calc(58px + env(safe-area-inset-bottom));z-index:760;display:flex;flex-direction:column;gap:10px;align-items:flex-end}
.control-stack{overflow:hidden;border-radius:16px;box-shadow:0 4px 16px rgba(0,0,0,.20);border:1px solid rgba(220,226,223,.95);background:#fff}
/* All four controls (zoom in/out, tilt, drop-pin) are now stroked SVGs on the
   same 22px/round-cap grid via .map-control svg below — font-size/font-weight
   were sizing the +/− TEXT glyphs these buttons used to render. */
.map-control{width:48px;height:48px;border:0;background:#fff;display:grid;place-items:center;cursor:pointer;color:#222a27}
.map-control + .map-control{border-top:1px solid var(--line)}
.map-control:hover{background:#f2f5f4}
.map-control.active{color:var(--teal)}
.map-control svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.locate-control,.fullscreen-control{width:52px;height:52px;border-radius:50%;border:1px solid rgba(220,226,223,.95);background:#fff;box-shadow:0 5px 18px rgba(0,0,0,.22);display:grid;place-items:center;cursor:pointer;touch-action:manipulation}
.locate-control{color:var(--teal)}
.fullscreen-control{color:var(--ink)}
.locate-control svg,.fullscreen-control svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.layer-switcher{position:fixed;left:18px;bottom:calc(58px + env(safe-area-inset-bottom));z-index:740;display:flex;flex-direction:column-reverse;gap:8px;align-items:flex-start}
.layer-badge{border:1px solid var(--line);background:rgba(255,255,255,.94);border-radius:16px;box-shadow:0 4px 16px rgba(0,0,0,.16);padding:9px 11px;font-size:11px;font-weight:800;color:#313a36;display:flex;align-items:center;gap:8px;cursor:pointer}
.layer-badge:hover{background:#f7fbfa}
.layer-badge .thumb{width:34px;height:34px;border-radius:9px;border:1px solid #b6c7c2;transition:background .18s ease, border-color .18s ease}
.layer-badge .thumb.street{background:linear-gradient(135deg,#d9f0e2 0 45%,#f8f1d7 45% 62%,#c4d9ef 62% 100%)}
.layer-badge .thumb.satellite{background:linear-gradient(135deg,#526447,#91a36e 35%,#c7b080 60%,#4f7f8e 100%);border-color:#8aa28b}
.credit-bar{position:fixed;left:18px;bottom:calc(10px + env(safe-area-inset-bottom));z-index:742;white-space:nowrap;font-size:11px;font-weight:700;background:rgba(255,255,255,.85);border:1px solid var(--line);border-radius:999px;padding:5px 11px;box-shadow:0 2px 10px rgba(0,0,0,.12);backdrop-filter:blur(6px);pointer-events:auto}
.credit-bar a{pointer-events:auto;color:#16697b;text-decoration:none}
.credit-bar a strong{font-weight:800}
.credit-bar a:hover{text-decoration:underline}

.school-photo{width:100%;height:165px;object-fit:cover;display:block;background:linear-gradient(135deg,#d9f0e2,#b7d6f0)}
.school-hero{overflow:hidden;border-radius:20px;border:1px solid var(--line);margin-bottom:14px;background:#edf4f2}
.school-hero .photo-caption{padding:9px 12px;font-size:11px;color:var(--muted);font-weight:700;background:#fff}
.school-thumb{width:54px;height:44px;border-radius:12px;object-fit:cover;border:1px solid var(--line);flex:0 0 auto;background:#edf4f2}
.path-photo{width:64px;height:54px;border-radius:14px;object-fit:cover;border:1px solid var(--line);flex:0 0 auto;background:#edf4f2}
.panel-filter-row{display:flex;gap:8px;overflow-x:auto;padding:0 0 12px;margin-bottom:12px;scrollbar-width:none;border-bottom:1px solid var(--line)}
.panel-filter-row::-webkit-scrollbar{display:none}
.panel-filter{white-space:nowrap;border:1px solid #d5dedb;background:#fff;color:#232a28;border-radius:999px;padding:8px 12px;font-size:11px;font-weight:800;cursor:pointer;touch-action:manipulation}
.panel-filter.active{border-color:var(--teal);background:#eaf6f8;color:var(--teal)}
.acct-tabs{display:flex;gap:0;border-bottom:1px solid var(--line);margin:0 -18px 16px;padding:0 18px;overflow-x:auto;scrollbar-width:none;flex-shrink:0}
.acct-tabs::-webkit-scrollbar{display:none}
.acct-tab{flex:none;border:none;background:transparent;padding:11px 14px;font-size:13px;font-weight:800;color:var(--muted);cursor:pointer;white-space:nowrap;border-bottom:2.5px solid transparent;margin-bottom:-1px;touch-action:manipulation;transition:color .15s,border-color .15s}
.acct-tab:hover{color:var(--ink)}
.acct-tab.active{color:#16697b;border-bottom-color:#16697b}
.acct-pane[hidden]{display:none}

@media (max-width:900px){
  /* Layout reflows to a column here, so the right inset is a fixed reflow value
     rather than the badge-derived --shell-clear (badge is hidden below 640). */
  .search-shell{flex-direction:column;gap:10px;right:84px}
  .search-wrap{width:100%}
  .pill-strip{width:100%;padding-top:0}
  /* Sit the hint below the stacked search bar + pill strip (see clamp below) */
  .hint{right:84px;max-width:none;top:calc(150px + env(safe-area-inset-top));z-index:755}
}
@media (max-width:640px){
  .search-shell{left:12px;right:12px;top:calc(12px + env(safe-area-inset-top))}
  .search-wrap{padding-right:0}
  .search-input{font-size:16px}
  /* SC 2.5.8 Target Size — keep tap targets >=44px even on the narrow mobile
     search bar (the avatar and icon buttons were shrunk to 32/38px here, below
     the minimum). The bar is 56px tall, so 44px controls fit; padding/gap trim
     keeps everything on one row. */
  .search-avatar{display:grid;width:40px;height:40px;font-size:13px;margin-right:2px}
  .brand-badge{display:none}
  .search-bar{padding:0 4px;gap:1px}
  .icon-btn{width:44px;height:44px}
  .lang-btn{min-width:40px}
  .hint{left:12px;right:12px;max-width:none;top:calc(158px + env(safe-area-inset-top));padding:10px 42px 10px 14px;font-size:12px;line-height:1.35}
  .panel-title{font-size:20px}
  .actions{grid-template-columns:1fr}
  .mini-actions{grid-template-columns:1fr 1fr 1fr}
  .layer-switcher{left:12px;bottom:calc(52px + env(safe-area-inset-bottom))}
  .credit-bar{left:12px;bottom:calc(10px + env(safe-area-inset-bottom));font-size:10px;padding:4px 9px}
  .maplibregl-ctrl-bottom-right{right:12px}
  .map-controls{right:12px;bottom:calc(52px + env(safe-area-inset-bottom))}
  .link-grid{grid-template-columns:1fr}
}

/* Narrowest phones: nudge the hint down once more so it clears the wrapped UI */
@media (max-width: 390px) {
  .hint {
    top: calc(166px + env(safe-area-inset-top));
  }
}
.zone-label{background:rgba(255,255,255,.92);border:1px solid rgba(0,0,0,.15);border-radius:6px;padding:4px 8px;font-size:12px;font-weight:700;color:#1f2523;box-shadow:0 2px 6px rgba(0,0,0,.15);pointer-events:none}

/* ── MapLibre GL overrides ───────────────────────────────────── */
.maplibregl-ctrl-attrib{font-size:9px}
.maplibregl-ctrl-scale{border-color:#aaa;font-size:9px;background:rgba(255,255,255,.7)}
.maplibregl-ctrl-bottom-left,.maplibregl-ctrl-bottom-right{z-index:741}
.maplibregl-ctrl-bottom-right{right:18px;bottom:calc(10px + env(safe-area-inset-bottom))}
/* Zone tooltip popup: strip default MapLibre popup chrome */
.zone-tooltip-popup .maplibregl-popup-content{padding:0;background:transparent;border-radius:0;box-shadow:none}
.zone-tooltip-popup .maplibregl-popup-tip{display:none}
.zone-tooltip-popup{pointer-events:none}
.clear-pin-btn{position:fixed;bottom:calc(24px + env(safe-area-inset-bottom));left:50%;transform:translateX(-50%);z-index:850;background:#1f2523;color:#fff;border:none;border-radius:999px;padding:10px 20px;font-size:13px;font-weight:700;box-shadow:0 4px 16px rgba(0,0,0,.35);cursor:pointer;white-space:nowrap;touch-action:manipulation}
.clear-pin-btn:hover{background:#333}

/* ── Boot loading / error states ─────────────────────────── */
.dm-boot{position:fixed;inset:0;z-index:1000;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;padding:24px;text-align:center;background:#dceee8;color:var(--ink);font-family:Sora,system-ui,-apple-system,Segoe UI,sans-serif}
.dm-boot-spinner{width:34px;height:34px;border-radius:50%;border:3px solid rgba(29,130,150,.25);border-top-color:var(--teal);animation:dm-spin .8s linear infinite}
@keyframes dm-spin{to{transform:rotate(360deg)}}
/* SC 1.4.3 — #67706b (--muted) on the #dceee8 boot background is only 4.25:1;
   #5b6360 lifts it to ~4.9:1 for the boot/loading text. */
.dm-boot-text{max-width:340px;font-size:14px;font-weight:600;line-height:1.5;color:#5b6360}
.dm-boot-error .dm-boot-text{color:var(--ink)}
.dm-boot-retry{margin-top:4px;border:0;border-radius:13px;background:var(--teal);color:#fff;font-size:13px;font-weight:800;padding:11px 22px;cursor:pointer}
.dm-boot-retry:hover{background:var(--teal-dark)}
@media (prefers-reduced-motion:reduce){.dm-boot-spinner{animation-duration:1.6s}}

/* ── WCAG 2.2 AA ─────────────────────────────────────────── */

/* Utility */
.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}
/* Skip link — hidden until focused, then slides into view (SC 2.4.1) */
.skip-link{position:absolute;top:-100%;left:8px;z-index:9999;padding:10px 18px;background:#16697b;color:#fff;font-size:14px;font-weight:700;border-radius:0 0 8px 8px;text-decoration:none;white-space:nowrap}
.skip-link:focus{top:0}

/* 2.4.7 / 2.4.11 Focus visible & not obscured */
*:focus{outline:none}
*:focus-visible{outline:3px solid #16697b;outline-offset:2px;border-radius:3px}
/* The address field — the widget's primary control — used to suppress this
   shared ring outright and rely on .search-bar:focus-within's border-color
   tint alone, which composites to ~1.4:1 against the unfocused border on a
   1px hairline: not a perceivable state change. The ring now applies like
   everywhere else; .search-bar's own box-shadow (below) gives it a second,
   stronger indicator since the ring sits on the small input, not the pill. */
/* SC 2.1.1 / 2.4.7 — a focused map marker gets a high-contrast ring (white halo
   + dark stroke) so it stays identifiable over satellite imagery, where a plain
   teal outline around a coloured circle all but disappears.
   MapLibre adds .maplibregl-marker to OUR OWN element — the same div that
   carries role="button" — so this must be a compound selector. It was written
   with a child combinator (`.maplibregl-marker > [role=button]`), which can
   never match: the whole halo was dead code and focused pins fell back to the
   generic 3px outline. The z-index lift below only orders pins against each
   other; it cannot raise one above the fixed chrome (#map is its own stacking
   context), which is why the JS pans a focused pin into the clear (SC 2.4.11). */
.maplibregl-marker:focus-within{z-index:5}
.maplibregl-marker[role="button"]:focus-visible{
  outline:3px solid #16697b;outline-offset:3px;
  box-shadow:0 0 0 3px #fff,0 0 0 6px #16697b,0 3px 10px rgba(0,0,0,.35)!important;
}
.search-bar:focus-within{border-color:rgba(29,130,150,.45);box-shadow:0 0 0 3px #16697b,0 4px 18px rgba(0,0,0,.18)}
/* panel-head is ~80px tall — scroll-margin must exceed it so focused items aren't obscured (SC 2.4.11) */
.panel-body *:focus-visible{scroll-margin-top:90px}
.drop-item:focus-visible{outline:2px solid #1d8296;outline-offset:-2px;border-radius:0}

/* 2.5.8 Touch targets — minimum 44×44 px */
.icon-btn{width:44px;height:44px}
.close-btn,.back-btn{width:44px;height:44px}
.hint button{width:44px;height:44px;top:4px;right:4px}
.panel-filter{min-height:44px;display:inline-flex;align-items:center}

/* 1.4.3 Contrast — #16697b gives ~5.6:1 on white, safe for all text sizes */
.status{color:#16697b}
.pill.active{color:#16697b}
.panel-filter.active{color:#16697b;background:#eaf6f8}
.credit-bar a{color:#16697b}
.search-input::placeholder{color:#4a5550;opacity:1}
/* panel-kicker: 10px/800 weight on white needs #16697b (5.8:1) not --teal (4.2:1) */
.panel-kicker{color:#16697b}
/* mini-link: --teal on #f2f7f7 is 3.9:1 — fails; #16697b on #f2f7f7 is 5.4:1 */
.mini-link{color:#16697b}
/* btn.secondary and btn.light: --teal on near-white backgrounds fails 4.5:1 */
.btn.secondary,.btn.light{color:#16697b}
/* lang-opt.active: hardcode rather than var(--teal) so a future regression
   that unclamps --teal can't drag this back below 4.5:1 */
.lang-opt.active{color:#16697b}

/* Pressed state — `-webkit-tap-highlight-color:transparent` (top of file)
   deliberately removes the browser's default tap flash, but nothing here ever
   replaced it: no control in the widget acknowledges a press before its
   click/tap actually completes. `scale` (not transform) so it composes with
   any translate/rotate a control already carries (.school-arrow's hover,
   the expanded-chevron rotate) instead of overwriting it. Inherits the
   reduced-motion guard below via the universal `*` transition-duration rule. */
.btn,.mini-link,.pill,.icon-btn,.map-control,.school-row,.path-card,.resource-link,.panel-filter,.lang-opt,.clear-pin-btn,.locate-control,.fullscreen-control,.layer-badge{
  transition-property:scale;transition-duration:150ms;transition-timing-function:ease-out;
}
.btn:active,.mini-link:active,.pill:active,.icon-btn:active,.map-control:active,.school-row:active,.path-card:active,.resource-link:active,.panel-filter:active,.lang-opt:active,.clear-pin-btn:active,.locate-control:active,.fullscreen-control:active,.layer-badge:active{scale:.96}

/* SC 2.3.3 Animation from Interactions — honor prefers-reduced-motion for every
   non-essential transition/animation (panel slide, overlay fade, toast, layer
   thumb, crosshair, tab underline, hover shadows). The boot spinner already
   slows itself above; here we drop motion to near-instant so the UI still
   updates state without movement for vestibular-sensitive users. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.001ms!important;scroll-behavior:auto!important}
  .side-panel,.overlay,.toast,.center-crosshair,.layer-badge .thumb,.acct-tab,.path-card,.school-row,.resource-link{transition:none!important}
  /* The boot spinner is a loading indicator (essential motion); keep it turning,
     just slower, matching the existing reduced-motion treatment above. */
  .dm-boot-spinner{animation-duration:1.6s!important}
}

/* ── RTL ──────────────────────────────────────────────────────────
   The JS sets dir="rtl" for ar/he/fa/ur/ps/ckb, but every inset in this file
   was physical, so an Arabic- or Urdu-reading parent got right-to-left text in
   a layout that never mirrored: the result panel still slid in from the left,
   the brand badge sat on top of the search bar's reading start, and the
   controls stayed on the wrong edge. These rules only ever apply under
   dir=rtl, so the LTR layout is untouched. Breakpoints mirror the physical
   rules above (which the higher-specificity [dir=rtl] selectors would
   otherwise override at every width). */
[dir=rtl] .skip-link{left:auto;right:8px}
[dir=rtl] .brand-badge{right:auto;left:var(--badge-edge)}
[dir=rtl] .search-shell{left:var(--shell-clear);right:16px}
[dir=rtl] .lang-picker{right:auto;left:0}
[dir=rtl] .hint{left:var(--shell-clear);right:16px;padding:12px 14px 12px 42px}
[dir=rtl] .side-panel{left:auto;right:0;transform:translateX(103%);border-right:0;border-left:1px solid var(--line);box-shadow:-14px 0 36px rgba(0,0,0,.22)}
[dir=rtl] .side-panel.open{transform:translateX(0)}
[dir=rtl] .map-controls{right:auto;left:18px;align-items:flex-start}
[dir=rtl] .layer-switcher{left:auto;right:18px;align-items:flex-end}
[dir=rtl] .credit-bar{left:auto;right:18px}
[dir=rtl] .maplibregl-ctrl-bottom-right{right:auto;left:18px}
/* Directional glyphs drawn in markup: the list chevron and the panel's back
   arrow both point the wrong way once the reading order flips. */
[dir=rtl] .school-arrow,[dir=rtl] .back-btn svg{transform:scaleX(-1)}
@media (max-width:900px){
  /* Badge still shows down to 640px, so the shell/hint clear the LEFT here. */
  [dir=rtl] .search-shell{left:84px;right:16px}
  [dir=rtl] .hint{left:84px;right:16px}
}
@media (max-width:640px){
  [dir=rtl] .search-shell{left:12px;right:12px}
  [dir=rtl] .hint{left:12px;right:12px;padding:10px 14px 10px 42px}
  [dir=rtl] .layer-switcher{left:auto;right:12px}
  [dir=rtl] .credit-bar{left:auto;right:12px}
  [dir=rtl] .map-controls{right:auto;left:12px}
  [dir=rtl] .maplibregl-ctrl-bottom-right{right:auto;left:12px}
}
/* Keep the 44px hint-close target (declared after the base rule above) on the
   reading-start side too. */
[dir=rtl] .hint button{left:4px;right:auto}
