/* ISPD admin panel. Self-contained (does not load styles.css) but shares the brand tokens. */
:root{
  --navy:#112D5E; --navy-deep:#0B1F42; --gold:#FFAC1F; --orange:#F66123;
  --paper:#F4F6FB; --white:#fff; --ink:#16203A; --muted:#4F5A78; --line:#D6DCEC; --line-strong:#B7C1DB;
  --ok:#17694B; --ok-bg:#E4F4EC; --warn:#8A5000; --warn-bg:#FFF1D6; --bad:#B42318; --bad-bg:#FDECEA;
  --display:'Sora',system-ui,sans-serif; --body:'Inter',system-ui,sans-serif;
  --r:10px; --shadow:0 10px 30px rgba(17,45,94,.12);
  --sidebar:250px; --topbar:56px;
}
*{box-sizing:border-box}
html{height:100%;scroll-padding-top:calc(var(--topbar) + 12px);scroll-padding-bottom:88px}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased;min-height:100%}
h1,h2,h3,h4{font-family:var(--display);color:var(--navy);line-height:1.2;letter-spacing:-.01em;margin:0 0 .5em}
h1{font-size:1.5rem;font-weight:700}
h2{font-size:1.15rem;font-weight:600}
h3,.h3{font-size:1rem;font-weight:600;font-family:var(--display);color:var(--navy)}
p{margin:0 0 .8em}
a{color:var(--navy);text-decoration-color:var(--gold);text-underline-offset:3px}
code{background:#E9EDF7;padding:1px 5px;border-radius:5px;font-size:.9em}
img,svg{max-width:100%}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:-999px}
.skip:focus{left:12px;top:12px;background:var(--navy);color:#fff;padding:10px 14px;border-radius:8px;z-index:200}
:focus-visible{outline:3px solid var(--navy-deep);outline-offset:2px;box-shadow:0 0 0 2px #fff;border-radius:6px}
.muted{color:var(--muted)}
.small-text{font-size:.85rem}
[hidden]{display:none !important}

/* ---------- brand ---------- */
.brand{display:flex;flex-direction:column;line-height:1.1;margin:0}
.brand .mark{font-family:var(--display);font-weight:700;color:var(--navy);letter-spacing:.08em;font-size:1.2rem}
.brand .sub{font-size:.68rem;color:var(--muted);letter-spacing:.08em;text-transform:uppercase}

/* ---------- auth screens ---------- */
.auth{min-height:100vh;display:grid;place-items:center;padding:24px;background:linear-gradient(160deg,var(--navy-deep),var(--navy) 60%,#1B3F7E)}
.auth-card{background:#fff;border-radius:16px;padding:32px;max-width:440px;width:100%;box-shadow:0 24px 60px rgba(0,0,0,.3)}
.auth-card .brand{margin-bottom:18px}
.auth-card h1{font-size:1.4rem}
.auth-card form{margin-top:16px}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:6px;background:#fff;color:var(--navy);padding:8px 14px;border-radius:8px;text-decoration:none;font-weight:600;font-size:.9rem;border:1px solid var(--line-strong);cursor:pointer;font-family:var(--body);line-height:1.3;min-height:38px;transition:background .15s ease,border-color .15s ease}
.btn:hover{background:#EEF2FA;border-color:var(--navy)}
.btn.primary{background:var(--navy);color:#fff;border-color:var(--navy)}
.btn.primary:hover{background:var(--navy-deep)}
.btn.gold{background:var(--gold);color:var(--navy-deep);border-color:var(--gold)}
.btn.gold:hover{background:#F39B00;border-color:#F39B00}
.btn.ghost{background:transparent}
.btn.danger{color:var(--bad);border-color:#E7A9A3}
.btn.danger:hover{background:var(--bad-bg);border-color:var(--bad)}
.btn.link{background:none;border:0;padding:8px 4px;text-decoration:underline;text-decoration-color:var(--gold);text-underline-offset:3px;font-weight:500}
.btn.small{padding:5px 10px;font-size:.82rem;min-height:32px}
.btn.icon{padding:6px 10px}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.55;cursor:not-allowed}
.actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:14px}
.actions.end{justify-content:flex-end}

/* ---------- forms ---------- */
.field{margin-bottom:16px;display:flex;flex-direction:column}
.field label,.field .label{font-size:.86rem;font-weight:600;color:var(--navy);margin-bottom:4px}
.field .req{color:var(--bad);font-weight:700;margin-left:2px}
input:not([type=checkbox]):not([type=radio]),select,textarea{font-family:var(--body);font-size:.95rem;padding:9px 11px;border:1px solid var(--line-strong);border-radius:8px;background:#fff;color:var(--ink);width:100%;transition:border-color .15s ease,box-shadow .15s ease}
input:focus,select:focus,textarea:focus{border-color:var(--navy)}
input[readonly]{background:#EEF1F8;color:var(--muted)}
textarea{min-height:76px;resize:vertical;line-height:1.5}
textarea.autogrow{overflow:hidden;resize:none}
.help{font-size:.82rem;color:var(--muted);margin:4px 0 0}
.counter{font-size:.78rem;color:var(--muted);margin:3px 0 0;text-align:right;font-variant-numeric:tabular-nums}
.counter.over{color:var(--bad);font-weight:600}
.field.invalid input,.field.invalid textarea,.field.invalid select{border-color:var(--bad);background:#FFF8F7}
.field-error{color:var(--bad);font-size:.84rem;font-weight:600;margin:4px 0 0}
.field-error::before{content:"⚠ ";}
.check{flex-direction:row;align-items:center;gap:10px}
.check input{width:20px;height:20px;margin:0;accent-color:var(--navy)}
.check label{margin:0}
.form-status{margin:12px 0 0;font-weight:600;color:var(--ok);min-height:1.3em;font-size:.9rem}
.form-status.bad{color:var(--bad)}
.error-summary{background:var(--bad-bg);border:1px solid #E7A9A3;border-radius:var(--r);padding:14px 18px;margin-bottom:18px}
.error-summary h2{color:var(--bad);font-size:1rem;margin-bottom:6px}
.error-summary ul{margin:0;padding-left:18px}
.error-summary button{display:inline-block;min-height:24px;background:none;border:0;padding:2px 0;color:var(--bad);text-decoration:underline;cursor:pointer;font:inherit;text-align:left}
.warn-summary{background:var(--warn-bg);border:1px solid #F2C879;border-radius:var(--r);padding:12px 18px;margin-bottom:18px;font-size:.9rem}
.draft-recovery{background:var(--warn-bg);border:1px solid #F2C879;border-radius:var(--r);padding:14px 18px;margin-bottom:18px;font-size:.9rem}
.draft-recovery p{margin:0}
.draft-recovery .actions{margin-top:12px}

/* editor structure */
.editor fieldset{border:1px solid var(--line);border-radius:var(--r);padding:16px 18px 6px;margin:0 0 18px;background:#fff;min-width:0}
.editor fieldset fieldset{background:#FAFBFE}
.editor legend{font-family:var(--display);font-weight:600;color:var(--navy);padding:0 6px;font-size:.98rem}
.editor .group-help{margin:-4px 0 12px;font-size:.84rem;color:var(--muted)}
.pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:640px){.pair{grid-template-columns:1fr}}
.list{margin:0;padding:0;list-style:none;counter-reset:item}
.list-item{border:1px solid var(--line);border-radius:var(--r);margin-bottom:10px;background:#fff}
.list-item>summary{cursor:pointer;padding:10px 14px;font-weight:600;display:flex;align-items:center;gap:10px;list-style:none}
.list-item>summary::-webkit-details-marker{display:none}
.list-item>summary .marker{color:var(--orange);font-size:.9rem;flex:0 0 auto;transition:transform .15s ease}
.list-item>summary .marker::before{content:"▸"}
.list-item[open]>summary .marker{transform:rotate(90deg)}
.list-item>summary .idx{color:var(--muted);font-weight:500;font-size:.85rem;min-width:1.6em}
.list-item>summary .sum{flex:1;font-weight:500;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.list-item>summary .sum:empty::before{content:"(empty)";color:var(--muted)}
.list-item .item-body{padding:12px 14px 4px;border-top:1px solid var(--line)}
.item-tools{display:flex;gap:6px;flex-wrap:wrap;padding:0 14px 12px;justify-content:flex-end}
.list-add{margin:4px 0 14px}
.list-empty{color:var(--muted);font-size:.9rem;margin:0 0 8px}
.list-item.flash{animation:flash .6s ease}
@keyframes flash{from{background:var(--warn-bg)}to{background:#fff}}

/* image field */
.image-field{display:grid;grid-template-columns:180px 1fr;gap:14px;align-items:start}
.image-thumb{width:180px;height:130px;border:1px solid var(--line);border-radius:8px;background:#EEF1F8 repeating-conic-gradient(#E3E7F2 0 25%,#F4F6FB 0 50%) 0 0/16px 16px;display:grid;place-items:center;overflow:hidden;color:var(--muted);font-size:.78rem;text-align:center;position:relative}
.image-thumb img{width:100%;height:100%;object-fit:cover}
.image-thumb.has-image{cursor:crosshair;touch-action:none}
.image-field .field{margin-bottom:10px}
@media(max-width:520px){.image-field{grid-template-columns:1fr}.image-thumb{width:100%;height:180px}}

/* focus point (image field extension) */
.focal-block{border-top:1px solid var(--line);margin-top:14px;padding-top:12px}
.focal-title{font-size:.9rem;margin:0 0 4px}
.focal-fields{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.focal-fields .field{margin-bottom:6px}
@media(max-width:520px){.focal-fields{grid-template-columns:1fr}}
.focal-status{font-size:.82rem;color:var(--muted);margin:6px 0 0;font-variant-numeric:tabular-nums}
.focal-crosshair{position:absolute;width:22px;height:22px;margin:-11px 0 0 -11px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 2px var(--navy),0 1px 4px rgba(0,0,0,.4);pointer-events:none}
.focal-crosshair::before,.focal-crosshair::after{content:"";position:absolute;background:var(--navy)}
.focal-crosshair::before{left:50%;top:2px;bottom:2px;width:2px;margin-left:-1px}
.focal-crosshair::after{top:50%;left:2px;right:2px;height:2px;margin-top:-1px}

/* colour field: swatch + hex text (the accessible source of truth) + live contrast readout */
.color-row{display:flex;align-items:stretch;gap:8px}
.color-swatch-wrap{display:inline-flex;flex:0 0 auto}
/* Beats the generic input width:100% rule above (equal specificity, later in source is not reliable across bundlers,
   so the extra class keeps this unambiguous). */
.color-swatch-wrap input[type=color]{-webkit-appearance:none;appearance:none;width:42px;height:42px;min-width:42px;padding:2px;border:1px solid var(--line-strong);border-radius:8px;background:#fff;cursor:pointer}
.color-swatch-wrap input[type=color]::-webkit-color-swatch-wrapper{padding:0}
.color-swatch-wrap input[type=color]::-webkit-color-swatch{border:0;border-radius:5px}
.color-swatch-wrap input[type=color]::-moz-color-swatch{border:0;border-radius:5px}
.color-row input[type=text]{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;text-transform:uppercase}
.color-empty-note{margin:8px 0 0;font-style:italic}
/* Contrast table: a real <table> (row navigable, scope=row headers) rather than a flat list, so a
   screen reader user can pull it up in the rotor and read "where it's used" / "result" per row. */
.color-contrast-table{width:100%;border-collapse:collapse;margin:10px 0 0;font-size:.85rem}
.color-contrast-table th,.color-contrast-table td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--line);vertical-align:middle}
.color-contrast-table thead th{font-size:.72rem;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);font-weight:600;border-bottom:2px solid var(--line)}
.color-contrast-table tbody th{font-weight:500;color:var(--ink)}
.color-contrast-table .contrast-ratio{font-variant-numeric:tabular-nums;font-weight:600;color:var(--ink)}
/* Word + number + glyph + colour, never colour alone: the badge always carries text ("Passes" /
   "Needs attention" / "Decoration only"), the glyph beside it is decorative (aria-hidden). Never set
   this text's own colour to the value under test. */
.color-info-note{font-size:.82rem;color:var(--muted);margin:8px 0 0;padding:8px 10px;background:#F4F6FB;border-radius:8px}

/* range field: slider + number, always paired with visible text */
.range-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.range-row input[type=range]{flex:1;min-width:140px;accent-color:var(--navy);height:32px;padding:0}
.range-num-wrap{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto}
.range-num-wrap input[type=number]{width:5.5em}
.range-unit{color:var(--muted);font-size:.9rem}
.range-foot{display:flex;align-items:center;gap:12px;margin-top:6px}
.range-readout{font-weight:700;color:var(--navy);font-variant-numeric:tabular-nums;font-family:var(--display)}

/* order field (reorderable, showable/hidable sections) */
.order-list{margin:0;padding:0;list-style:none}
.order-row{display:flex;gap:4px;align-items:center;margin-bottom:8px;border:1px solid var(--line);border-radius:var(--r);background:#fff;padding:6px 10px 6px 2px}
.order-row .idx{color:var(--muted);font-weight:500;font-size:.85rem;min-width:1.6em;text-align:right}
.order-main{flex:1;min-width:0}
.order-row .check{margin:0}
.order-row .check label{font-weight:500;color:var(--ink)}
.order-row.flash{animation:flash .6s ease}
/* Hidden sections stay in the list (never removed — that would drop focus and make them impossible
   to bring back); dimming is paired with visible "— hidden from the page" text, never opacity alone. */
.order-row.is-hidden{opacity:.62}
.order-row .hidden-note{color:var(--muted);font-weight:400;font-style:italic}

/* ---------- app shell ---------- */
#app{min-height:100vh;display:grid;grid-template-columns:var(--sidebar) 1fr;grid-template-rows:var(--topbar) 1fr;grid-template-areas:"top top" "side main"}
.topbar{grid-area:top;display:flex;align-items:center;gap:16px;padding:0 18px;background:#fff;border-bottom:1px solid var(--line);position:sticky;top:0;z-index:30}
.topbar .brand{flex-direction:row;gap:8px;align-items:baseline}
.topbar-right{margin-left:auto;display:flex;gap:10px;align-items:center}
.menu-toggle{display:none}
.burger{display:inline-block;width:18px}
.burger span{display:block;width:18px;height:2px;background:var(--navy);margin:3px 0}
.sidebar{grid-area:side;background:var(--navy-deep);color:#fff;padding:14px 12px;display:flex;flex-direction:column;position:sticky;top:var(--topbar);height:calc(100vh - var(--topbar));overflow-y:auto}
.nav-list,.nav-list ul{list-style:none;margin:0;padding:0}
/* A flex column that fills the sidebar, which is what gives .nav-end a gap to push into. */
.nav-list{display:flex;flex-direction:column;flex:1 1 auto}
.nav-list li{margin:0}
/* Sign out is a button because it does something rather than goes somewhere; it is dressed as a row
   of the same list because that is where it now lives. */
.nav-list a,.nav-list button{display:block;width:100%;text-align:left;background:none;border:0;font:inherit;color:#fff;text-decoration:none;padding:8px 12px;border-radius:8px;font-weight:500;font-size:.93rem;cursor:pointer}
.nav-list a:hover,.nav-list button:hover{background:rgba(255,255,255,.1)}
.nav-list a[aria-current="page"]{background:var(--gold);color:var(--navy-deep);font-weight:600}
/* Pins the account rows to the bottom without moving them in the DOM, so the reading order and the
   visual order stay the same one. */
.nav-end{margin-top:auto;border-top:1px solid rgba(255,255,255,.15);padding-top:10px}
/* A finger needs 44px; the panel is used on a phone. */
@media(any-pointer:coarse){.nav-list a,.nav-list button{min-height:44px;display:flex;align-items:center}}
.sidebar :focus-visible{outline-color:#fff;box-shadow:0 0 0 2px var(--navy-deep)}
.nav-heading{display:block;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.65);padding:12px 12px 4px;font-weight:600}
.nav-group ul a{padding-left:22px;font-size:.88rem}
/* A gap after the group, so the collections below it are not read as more of its children. */
.nav-group{margin-bottom:8px}
.user-email{color:rgba(255,255,255,.8);font-size:.82rem;word-break:break-all;margin:6px 0 0;padding:0 12px}
main#admin-main{grid-area:main;padding:24px 28px 60px;min-width:0;max-width:1240px;width:100%}
main#admin-main:focus{outline:none}
@media(max-width:900px){
  #app{grid-template-columns:1fr;grid-template-areas:"top" "main"}
  .menu-toggle{display:inline-flex}
  .sidebar{position:fixed;top:var(--topbar);left:0;bottom:0;width:min(300px,85vw);height:auto;transform:translateX(-105%);visibility:hidden;transition:transform .2s ease,visibility 0s linear .2s;z-index:40;box-shadow:var(--shadow)}
  .sidebar.open{transform:none;visibility:visible;transition-delay:0s}
  main#admin-main{padding:18px 16px 60px}
  .topbar-right .btn{display:none}
  html{scroll-padding-bottom:112px}
}
@media(prefers-reduced-motion:reduce){*{transition:none !important;animation:none !important}}
@media (prefers-reduced-motion:reduce){.spinner{animation:none}}

/* ---------- page layout ---------- */
.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-bottom:18px}
.page-head h1{margin-bottom:2px}
.page-head .sub{color:var(--muted);margin:0;font-size:.9rem}
.card{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:20px 22px;margin-bottom:18px}
.card h2{font-size:1.05rem}
.sticky-bar{position:sticky;bottom:0;background:rgba(255,255,255,.96);border-top:1px solid var(--line);padding:12px 0;margin-top:10px;display:flex;gap:10px;flex-wrap:wrap;align-items:center;z-index:5;backdrop-filter:blur(6px)}
.sticky-bar .dirty{font-size:.85rem;color:var(--warn);font-weight:600;margin-left:auto}
.badge{display:inline-block;padding:3px 10px;border-radius:999px;font-size:.74rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;text-decoration:none}
.badge.ok{background:var(--ok-bg);color:var(--ok)}
.badge.warn{background:var(--warn-bg);color:var(--warn)}
.badge.bad{background:var(--bad-bg);color:var(--bad)}
.badge.neutral{background:#E9EDF7;color:var(--muted)}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:0 0 18px}
.stat{background:#fff;border-radius:var(--r);padding:14px 16px;border:1px solid var(--line)}
.stat dt{font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600}
.stat dd{margin:4px 0 0;font-family:var(--display);font-weight:700;font-size:1.5rem;color:var(--navy);word-break:break-word}
.stat dd.text{font-size:1rem}
.quick-links{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.quick-links a{display:block;background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:14px 16px;text-decoration:none;font-weight:600}
.quick-links a span{display:block;font-weight:400;color:var(--muted);font-size:.85rem;margin-top:2px}
.quick-links a:hover{border-color:var(--navy)}

/* ---------- tables ---------- */
.toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-bottom:14px}
.toolbar .field{margin:0;min-width:160px}
.toolbar .grow{flex:1;min-width:220px}
.table-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r);background:#fff}
table.data{width:100%;border-collapse:collapse;min-width:720px}
table.data th,table.data td{text-align:left;padding:10px 12px;border-bottom:1px solid var(--line);font-size:.9rem;vertical-align:top}
table.data thead th{background:var(--navy);color:#fff;font-family:var(--display);font-size:.76rem;letter-spacing:.05em;position:sticky;top:0;white-space:nowrap}
table.data tbody tr:hover{background:#F8FAFE}
table.data td small{color:var(--muted);display:block;font-size:.8rem}
table.data td .row-actions{display:flex;gap:6px;flex-wrap:wrap}
table.data select,table.data textarea{font-size:.85rem;padding:6px 8px;min-width:120px}
table.data textarea{min-height:52px;min-width:180px}
.pill{display:inline-block;padding:2px 9px;border-radius:999px;font-size:.72rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.pill.new{background:var(--warn-bg);color:var(--warn)}
.pill.contacted{background:rgba(17,45,94,.12);color:var(--navy)}
.pill.enrolled{background:var(--ok-bg);color:var(--ok)}
.pill.closed{background:#E9EDF7;color:var(--muted)}
.empty{padding:36px;text-align:center;color:var(--muted)}
.row-title{font-weight:600}
.row-title a{text-decoration:underline}
.row-title a:hover{text-decoration:underline}

/* ---------- collection row lists (Programmes, Coaches, Testimonials) ---------- */
/* One row per item instead of a 720px-wide table. On a phone that table pushed Delete off the right
   edge, so reaching it meant scrolling a table sideways; here everything wraps down the page. */
.row-list{list-style:none;margin:0 0 18px;padding:0;border:1px solid var(--line);border-radius:var(--r);background:#fff}
.row-list:empty{display:none}
.row-list .row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 12px;border-bottom:1px solid var(--line)}
.row-list .row:last-child{border-bottom:0}
.row-list .row:hover{background:#F8FAFE}
.row-main{flex:1 1 220px;min-width:0}
.row-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin:0}
.row-name{font-weight:600;color:var(--navy);text-decoration:underline;text-underline-offset:2px}
.row-sub{margin:2px 0 0;color:var(--muted);font-size:.82rem;word-break:break-word}
/* The public address is worth keeping — it is permanent and it lost its own column — but it is a
   reference, not the headline. As a tinted code chip it was the loudest thing in a row whose point
   is the name, so it keeps the monospace (it is a literal address) and drops the chip. */
.row-sub code{background:none;padding:0;font-size:.95em;color:var(--muted)}
/* A fixed box whether or not there is a picture in it, so the names stay on one line down the list. */
.row-thumb{flex:0 0 auto;display:block;width:48px;height:48px;border-radius:8px;overflow:hidden;background:#EEF1F8;border:1px solid var(--line)}
.row-thumb img{display:block;width:100%;height:100%;object-fit:cover}
.row-tools{display:flex;gap:6px;flex-wrap:wrap;margin-left:auto}
.row-tools .btn.arrow{min-width:34px;padding:5px 8px;justify-content:center;font-size:1rem}
@media(any-pointer:coarse){.row-tools .btn.arrow{min-width:44px}}
.list-summary{color:var(--muted);font-size:.9rem;margin:0 0 12px;max-width:70ch}

/* ---------- dialogs ---------- */
dialog{border:0;border-radius:14px;padding:0;max-width:min(720px,94vw);width:100%;box-shadow:0 30px 80px rgba(0,0,0,.35);color:var(--ink)}
dialog.wide{max-width:min(1100px,96vw)}
dialog[open]{display:flex;flex-direction:column;max-height:calc(100dvh - 32px)}
dialog::backdrop{background:rgba(11,31,66,.55)}
.dialog-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 20px;border-bottom:1px solid var(--line)}
.dialog-head h2{margin:0;font-size:1.05rem}
.dialog-body{padding:18px 20px;flex:1 1 auto;min-height:0;overflow:auto}
.dialog-foot{padding:12px 20px;border-top:1px solid var(--line);display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}

/* ---------- media ---------- */
.dropzone{border:2px dashed var(--line-strong);border-radius:var(--r);padding:22px;text-align:center;background:#fff;margin-bottom:16px}
.dropzone.over{border-color:var(--navy);background:#EEF2FA}
.dropzone p{margin:0 0 10px}
.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px;list-style:none;margin:0;padding:0}
.media-item{background:#fff;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;display:flex;flex-direction:column}
.media-item figure{margin:0;aspect-ratio:4/3;background:#EEF1F8 repeating-conic-gradient(#E3E7F2 0 25%,#F4F6FB 0 50%) 0 0/16px 16px;display:grid;place-items:center}
.media-item img{width:100%;height:100%;object-fit:cover}
.media-item .meta{padding:8px 10px;font-size:.78rem;color:var(--muted);word-break:break-all;flex:1}
.media-item .meta strong{display:block;color:var(--ink);font-size:.82rem}
.media-item .tools{display:flex;gap:4px;flex-wrap:wrap;padding:0 8px 8px}
.media-item .tools .btn{flex:1;justify-content:center}
.media-item.selected{outline:3px solid var(--gold)}
.progress{height:8px;background:#E9EDF7;border-radius:999px;overflow:hidden;margin:8px 0}
.progress>div{height:100%;background:var(--navy);width:0;transition:width .2s ease}

/* ---------- preview ---------- */
.preview-wrap{background:#E9EDF7;border:1px solid var(--line);border-radius:var(--r);padding:12px;display:flex;justify-content:center}
.preview-wrap iframe{background:#fff;border:1px solid var(--line-strong);border-radius:6px;width:100%;height:70vh;transition:width .2s ease}
.preview-wrap.mobile iframe{width:390px;max-width:100%}
.preview-wrap.narrow iframe{width:320px;max-width:100%}
.seg{display:inline-flex;border:1px solid var(--line-strong);border-radius:8px;overflow:hidden}
.seg button{border:0;background:#fff;padding:6px 12px;font:inherit;font-size:.85rem;font-weight:600;cursor:pointer;color:var(--navy)}
.seg button[aria-pressed="true"]{background:var(--navy);color:#fff}
.seg button:focus-visible{outline-offset:-3px;box-shadow:inset 0 0 0 5px #fff}

/* ---------- history ---------- */
.history{list-style:none;margin:0;padding:0}
.history li{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.history li:last-child{border:0}
.history time{font-weight:600}

/* ---------- toasts ---------- */
.toasts{position:fixed;right:16px;bottom:16px;display:flex;flex-direction:column;gap:8px;z-index:100;max-width:min(380px,92vw)}
.toast{background:var(--navy-deep);color:#fff;padding:11px 14px;border-radius:10px;box-shadow:var(--shadow);font-size:.9rem;display:flex;gap:10px;align-items:flex-start;border-left:4px solid var(--gold)}
.toast.ok{border-left-color:#3CC98A}
.toast.bad{border-left-color:#FF6B5B}
.toast button{margin-left:auto;background:none;border:0;color:#fff;cursor:pointer;font-size:1rem;line-height:1;padding:2px 4px;min-width:28px;min-height:28px}

/* publish */
.status-line{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:.95rem}
.spinner{display:inline-block;width:14px;height:14px;border:2px solid var(--line-strong);border-top-color:var(--navy);border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- drag-and-drop reordering (dnd.mjs) ---------- */
/* Handle: 44x44 target, grip drawn in CSS (navy dots on white ≈ 12:1). touch-action:none so the browser
   hands touch moves to the pointer events instead of scrolling. Keyboard users reorder with Move up / Move down —
   which is why the collection lists draw the handle as an aria-hidden <span>: it is a pointer affordance
   and nothing else, so it has no business being a tab stop. The editor's own lists still use a button. */
.drag-handle{display:inline-grid;place-items:center;width:44px;height:44px;padding:0;margin:0;background:transparent;border:1px solid transparent;border-radius:8px;color:var(--navy);cursor:grab;touch-action:none;flex:0 0 auto;-webkit-user-select:none;user-select:none}
.drag-handle:hover{background:#EEF2FA;border-color:var(--line-strong)}
.is-sorting .drag-handle{cursor:grabbing}
.drag-handle .grip{display:block;width:10px;height:16px;background:radial-gradient(circle,currentColor 1.7px,transparent 2px) 0 0/5px 5.4px}
/* Windows High Contrast strips background images; redraw the grip in the system button-text colour so the handle is not blank. */
@media (forced-colors:active){.drag-handle .grip{forced-color-adjust:none;background-image:radial-gradient(circle,ButtonText 1.7px,transparent 2px)}}
.sorting>*{transition:transform .15s ease}
.sorting>.dragging{transition:none;position:relative;z-index:3;opacity:.96}
.dragging{box-shadow:var(--shadow);outline:2px solid var(--navy);outline-offset:-2px;background:#fff}
.drop-placeholder{position:fixed;z-index:2;pointer-events:none;box-sizing:border-box;border:3px dashed var(--navy);border-radius:8px;background:rgba(255,172,31,.14)}
.is-sorting{cursor:grabbing;-webkit-user-select:none;user-select:none}
.is-sorting *{cursor:grabbing !important}

/* editor lists: handle sits beside each item, next to its summary */
.list-row{display:flex;gap:4px;align-items:flex-start;margin-bottom:10px;border-radius:var(--r)}
.list-row .item-main{flex:1;min-width:0}
.list-row .list-item{margin-bottom:0}
.list-row .drag-handle{margin-top:0}
.list-tools{display:flex;gap:6px;flex-wrap:wrap;margin:0 0 10px}

/* ---------- formatting toolbar ---------- */
.fmt-toolbar{display:flex;gap:4px;flex-wrap:wrap;margin:0 0 6px}
.fmt-btn{display:inline-flex;align-items:center;justify-content:center;gap:2px;min-height:32px;min-width:32px;padding:4px 10px;background:#fff;border:1px solid var(--line-strong);border-radius:6px;color:var(--navy);font:inherit;font-size:.85rem;font-weight:600;cursor:pointer;line-height:1.2}
.fmt-btn:hover{background:#EEF2FA;border-color:var(--navy)}
.fmt-btn b{font-weight:800}
.fmt-btn i{font-style:italic;font-family:Georgia,serif;font-weight:600}
/* any-pointer: a laptop with a touch screen also has a mouse, and pointer: alone would report the mouse. */
@media(any-pointer:coarse){.fmt-btn{min-height:44px;min-width:44px}.btn.small{min-height:44px}}

/* ---------- drop-to-upload on image fields ---------- */
.editor fieldset.image-fs{position:relative}
.image-fs .drop-hint{display:none;position:absolute;inset:0;margin:0;border-radius:var(--r);border:3px dashed var(--navy);background:rgba(244,246,251,.94);color:var(--navy);font-family:var(--display);font-weight:600;font-size:1rem;place-items:center;pointer-events:none;z-index:2}
.image-fs.drop-active .drop-hint{display:grid}
.image-fs .upload-status{margin:0 0 10px;min-height:0}
/* Keep the empty live region in the tree (display:none would hide it from screen readers); just drop its margin. */
.image-fs .upload-status:empty{margin:0}

/* ---------- click-to-edit ("Edit on the page") ----------
   The preview outlines every region the templates mark as editable and puts a labelled pencil
   button on it; activating one lands here, on the field that controls it. The landing cue is never
   colour alone: a gold rule down the side, a thicker border AND a "✎ Opened from the preview" line
   in words, so it reads the same in greyscale or high-contrast mode. */
.editor .found{position:relative;border-left:4px solid var(--gold);background:#FFFCF2;padding:10px 12px 4px 12px;border-radius:8px;box-shadow:0 0 0 1px var(--line-strong)}
.editor fieldset.found{padding-top:10px}
.found-note{display:flex;align-items:center;gap:2px;margin:0 0 6px;font-size:.8rem;font-weight:700;color:var(--warn);text-transform:uppercase;letter-spacing:.04em}
.found-remove{margin:10px 0 6px;padding-top:10px;border-top:1px dashed var(--line-strong)}
.found-remove .help{margin-top:6px;max-width:52ch}

/* The "Edit on the page" switch in the preview window. aria-pressed carries the state; the filled
   look and the wording are the visible half of it. */
.actions .btn.small[aria-pressed="true"]{background:var(--navy);color:#fff;border-color:var(--navy)}
.actions .btn.small[aria-pressed="true"]:hover{background:var(--navy-deep)}
.preview-wrap + .help,.actions + .help{margin:0 0 8px;max-width:78ch}

/* ---------- visual editing ("Change how the page looks") ----------
   The panel that sits above the preview while the visual editor is on, and the plain-English
   summary of the same overrides shown on the form. Everything here is a real control with a real
   name; nothing is carried by colour alone. The toolbar that floats over the page itself is not
   styled here — it lives inside the preview document, so its CSS is injected by admin/visual.mjs. */

.layout-field .form-status{margin:0 0 8px;color:var(--ink)}
.layout-list{list-style:none;margin:0 0 4px;padding:0;display:flex;flex-direction:column;gap:8px}
.layout-list li{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between;
  border:1px solid var(--line);border-radius:8px;background:#fff;padding:8px 10px;font-size:.9rem}


/* ==========================================================================
   THE FULL-SCREEN EDITOR  (public/admin/canvas.mjs)

   The site fills the window; a slim top bar and a narrow icon rail frame it. The admin's own
   header and sidebar are taken away with display:none — NOT `inert`, which propagates into nested
   browsing contexts and would make the whole rendered site non-focusable and invisible to
   assistive technology. Everything that stays on screen stays tabbable.

   #toasts, #status-live and #alerts are siblings of <main> and are deliberately left alone: an
   inert or hidden subtree is removed from the accessibility tree, and every announcement would
   die silently with no error and no symptom.
   ========================================================================== */
body.canvas-mode{overflow:hidden}
body.canvas-mode .topbar,body.canvas-mode .sidebar{display:none}
body.canvas-mode #app{grid-template-columns:1fr;grid-template-rows:1fr;grid-template-areas:"main"}
body.canvas-mode main#admin-main{padding:0;max-width:none;height:100vh;height:100dvh;overflow:hidden}

.cv{display:grid;grid-template-rows:auto 1fr;height:100%;background:var(--paper)}

.cv-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:8px 12px;background:#fff;border-bottom:1px solid var(--line-strong)}
.cv-top-end{margin-left:auto;display:flex;align-items:center;gap:8px}
/* #767F9C, not --line-strong: a 1.7:1 boundary is not a boundary (SC 1.4.11 wants 3:1 for the
   edge of a control), and these are brand-new controls rather than existing house style. */
.cv-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:36px;min-width:36px;padding:6px 12px;
  border:1px solid #767F9C;border-radius:8px;background:#fff;color:var(--navy-deep);
  font:600 .86rem/1.2 var(--body);text-decoration:none;cursor:pointer}
.cv-btn:hover{background:#EEF2FA;border-color:var(--navy-deep)}
.cv-btn[aria-pressed="true"]{background:var(--navy-deep);color:#fff;border-color:var(--navy-deep)}
/* aria-disabled, never disabled: a disabled Undo cannot take focus, and Undo is exactly where
   focus is sent after a section is hidden. */
.cv-btn[aria-disabled="true"]{color:#5B6880;background:#F2F4F8;border-color:#767F9C;cursor:default}
.cv-btn[aria-disabled="true"]:hover{background:#F2F4F8;border-color:#767F9C}
.cv-btn.cv-go{background:var(--gold);border-color:#8A5000;color:var(--navy-deep)}
.cv-btn.cv-go:hover{background:#F39B00}
.cv-ico{font-size:1rem;line-height:1}
.cv-seg{display:inline-flex;border:1px solid #767F9C;border-radius:8px;overflow:hidden}
.cv-seg-btn{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:6px 12px;margin:0;
  border:0;border-right:1px solid #767F9C;background:#fff;color:var(--navy-deep);
  font:600 .86rem/1.2 var(--body);cursor:pointer}
.cv-seg-btn:last-child{border-right:0}
.cv-seg-btn:hover{background:#EEF2FA}
.cv-seg-btn[aria-pressed="true"]{background:var(--navy-deep);color:#fff}
.cv-state{margin:0 4px;font:600 .86rem/1.2 var(--body);color:var(--muted);min-width:6.5em}
.cv-state.bad{color:var(--bad)}

/* Flex, not grid: the Pages panel is [hidden] most of the time, and a display:none grid item is
   not placed — so the stage slid into the panel's auto column and sized itself to the iframe's
   intrinsic 300px instead of filling the window. */
.cv-body{display:flex;min-height:0}
.cv-rail,.cv-panel{flex:0 0 auto}
.cv-stage{flex:1 1 auto;min-width:0}

/* role="group", not a landmark: these switch what you are working on rather than navigating. */
.cv-rail{background:var(--navy-deep);padding:8px 6px;overflow-y:auto}
.cv-rail ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.cv-rail-btn{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  width:62px;min-height:56px;padding:6px 2px;margin:0;
  border:1px solid transparent;border-radius:8px;background:transparent;color:#fff;
  font:600 .75rem/1.2 var(--body);text-align:center;text-decoration:none;cursor:pointer}
.cv-rail-btn .cv-ico{font-size:1.15rem}
.cv-rail-btn:hover{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.5)}
.cv-rail-btn[aria-expanded="true"]{background:#fff;color:var(--navy-deep)}
.cv-rail :focus-visible{outline:3px solid #fff;outline-offset:2px;box-shadow:0 0 0 3px var(--navy-deep)}

.cv-panel{width:min(280px,72vw);background:#fff;border-right:1px solid var(--line-strong);
  padding:12px 14px 18px;overflow-y:auto}
.cv-panel-head{display:flex;align-items:center;justify-content:space-between;gap:8px}
.cv-panel h2{font-size:1rem;margin:0}
.cv-panel .cv-sub{font-size:.8rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin:16px 0 4px}
.cv-panel-x{min-width:32px;min-height:32px;border:1px solid #767F9C;border-radius:8px;
  background:#fff;color:var(--navy-deep);font-size:1.1rem;line-height:1;cursor:pointer}
.cv-panel-x:hover{background:#EEF2FA;border-color:var(--navy-deep)}
.cv-list{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}
.cv-page,.cv-show{display:block;width:100%;min-height:36px;padding:8px 10px;
  border:1px solid #767F9C;border-radius:8px;background:#fff;color:var(--navy-deep);
  font:600 .86rem/1.25 var(--body);text-align:left;text-decoration:none;cursor:pointer}
.cv-page:hover,.cv-show:hover{background:#EEF2FA;border-color:var(--navy-deep)}
.cv-page[aria-current]{background:var(--navy-deep);color:#fff;border-color:var(--navy-deep)}
.cv-none{color:var(--muted);font-size:.84rem;padding:4px 2px}

/* Never transform:scale() the canvas — a 2px ring would become sub-pixel and disappear. */
.cv-stage{min-width:0;min-height:0;overflow:auto;display:flex;justify-content:center;background:#DEE4F1}
/* flex:1 1 auto, not width alone: an <iframe> has an intrinsic 300x150 size, and a flex item
   that only carries width:100% shrinks straight back to it. */
.cv-frame{border:0;flex:1 1 auto;width:100%;height:100%;background:#fff;display:block}
.cv-stage.cv-phone{padding:12px 0}
.cv-stage.cv-phone .cv-frame{flex:0 0 390px;width:390px;max-width:100%;height:calc(100% - 24px);
  border:1px solid var(--line-strong);border-radius:14px;box-shadow:var(--shadow)}
.cv-stage.cv-broken::after{content:"The page could not be drawn. Your changes are safe.";
  align-self:center;padding:20px;color:var(--ink);font-weight:600}

.cv-top :focus-visible,.cv-panel :focus-visible{outline:3px solid var(--navy-deep);outline-offset:2px;box-shadow:0 0 0 3px #fff}

/* At 320px a 62px rail leaves under 260px of canvas, and nothing useful fits beside it. */
@media(max-width:480px){
  .cv-body{flex-direction:column}
  .cv-rail,.cv-panel{flex:0 0 auto;width:auto}
  .cv-stage{flex:1 1 auto}
  .cv-rail{padding:6px}
  .cv-rail ul{flex-direction:row;justify-content:space-around}
  .cv-rail-btn{width:auto;flex:1 1 0;min-height:48px;flex-direction:row;gap:6px}
  .cv-panel{width:auto;border-right:0;border-bottom:1px solid var(--line-strong);max-height:44vh}
  .cv-top{padding:6px 8px}
  .cv-state{min-width:0}
}
@media (forced-colors: active){
  .cv-btn[aria-pressed="true"],.cv-seg-btn[aria-pressed="true"],.cv-page[aria-current]{
    forced-color-adjust:none;background:Highlight;color:HighlightText;border-color:HighlightText}
  .cv-rail{border-right:1px solid CanvasText}
  .cv-frame{border:1px solid CanvasText}
}
