/* ==========================================================================
   EDITORIAL CITY SYSTEM v2 — "PANELS" — shared layer (.ce-*)
   Used by all 21 city pages and houston.html. Render-blocking by design:
   these rules style above-the-fold content, so they must not be async.
   Per-city art motifs stay inline on their own page.

   v2 changes the CONTAINMENT, not the structure. Every section's existing
   .container becomes a physical panel: stepped surface, hairline border,
   restrained lift, generous internal padding. Sections no longer bleed into
   one another, so the page reads as a stack of digestible units.
   No class was renamed or removed; no HTML change is required.
   ==========================================================================

   STRUCTURAL CONTRACT — binding on anyone editing the 22 city HTML files.
   Nothing to change; just do not break it.

     1. Every section keeps a DIRECT-CHILD `<div class="container">`. That div
        is the panel. Content moved outside it silently loses its panel.
     2. `.ce-figure` must NEVER gain padding or a wrapper. `.ce-callouts li`
        carries inline, per-city `top:` percentages measured against that box
        (e.g. `<li style="top:26%;--lead:1.55rem">`). The card backdrop is a
        negative-inset ::before precisely so the box geometry is unchanged.
     3. `.ce-facts` keeps exactly 5 `<div>` children (Rating / Local since /
        Every crew / Coverage / Office hours), or the
        `:last-child { grid-column: 1 / -1 }` fallback misfires.
     4. `<body>` keeps BOTH `city-page` and `city-ed` — the token block below
        is scoped to `body.city-page.city-ed`.
     5. `.ce-facts dt`, `.ce-index dt`, `.ce-callouts li`, `.ce-quote footer`,
        `.ce-eyebrow` and `.breadcrumb` now render in their AUTHORED casing,
        because `text-transform: uppercase` was removed from them. Keep every
        one of those strings sentence case.
   ========================================================================== */

/* ==========================================================================
   0. Tokens
   Surface scale steps: ground -> panel -> raised -> hover.
   Every text tier below was contrast-checked against every surface above,
   including the brightest pixel of each gradient panel. Lowest pair actually
   used on a page: 5.85:1 (--ce-dim on the close panel's bloom). Lowest
   theoretical pair anywhere in the matrix: 4.91:1. AA body text needs 4.5:1.
   ========================================================================== */

body.city-page.city-ed {
    --ce-serif: 'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia, 'Times New Roman', serif;
    --ce-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;

    /* surfaces */
    --ce-ground: #0b0f17;   /* page behind the panels */
    --ce-surface: #141b29;  /* the panel itself */
    --ce-raised: #1c2434;   /* a card nested inside a panel */
    --ce-hover: #242e42;    /* nested card, hover / open state */
    --ce-thesis-surface: #121826;

    /* lines */
    --ce-line: rgba(255, 255, 255, 0.10);
    --ce-hair: rgba(255, 255, 255, 0.065);

    /* v1 aliases — DO NOT DELETE. The per-city <style> motifs read these:
       houston.html uses --ce-ink as the SVG rim behind its map nodes, and
       20 pages stroke their ground line with --ce-rule. --ce-ink now points
       at the panel because that is what the artwork actually sits on. */
    --ce-ink: var(--ce-surface);
    --ce-panel: var(--ce-surface);
    --ce-rule: var(--ce-line);

    /* accent */
    --ce-cyan: #5fe3e8;
    --ce-violet: #a387f3;
    --ce-cyan-soft: rgba(95, 227, 232, 0.24);
    --ce-cyan-wash: rgba(63, 199, 211, 0.08);

    /* text tiers */
    --ce-strong: rgba(255, 255, 255, 0.94);
    --ce-body: rgba(255, 255, 255, 0.80);
    --ce-dim: rgba(255, 255, 255, 0.66);
    --ce-faint: rgba(255, 255, 255, 0.58);

    /* geometry */
    --ce-gutter: clamp(0.7rem, 2.2vw, 1.5rem);   /* page edge -> panel edge */
    --ce-gap: clamp(1.25rem, 3vw, 2.25rem);      /* panel -> panel */
    --ce-pad: clamp(1.5rem, 4.2vw, 3.25rem);     /* inside a panel */
    --ce-pad-sm: clamp(1.05rem, 2.2vw, 1.6rem);  /* inside a nested card */
    --ce-r: clamp(14px, 1.6vw, 22px);            /* panel radius */
    --ce-r-sm: clamp(10px, 1.1vw, 14px);         /* nested card radius */
    --ce-lift:
        inset 0 1px 0 rgba(255, 255, 255, 0.04),
        0 1px 2px rgba(0, 0, 0, 0.4),
        0 20px 44px -28px rgba(0, 0, 0, 0.95);

    background: var(--ce-ground);
}

body.city-ed main {
    overflow-x: clip;
}

/* The shared footer ships at --dark-surface #141414, which is both lighter
   and warmer than the new #0b0f17 ground; the join read as an unintended
   band. #0f141d sits one step above the ground on the same cool ladder, so
   the footer reads as the final surface rather than a foreign slab.

   Specificity note: this MUST stay at (0,3,0). city-template.css:438 declares
   `body.city-page .footer { background: var(--dark-surface) }` at (0,2,0),
   and city-template.css is loaded AFTER this sheet (async preload at the
   bottom of every city <head>), so a matching (0,2,0) rule here loses on
   source order. The extra .city-page class is what wins the cascade — and it
   also keeps this scoped to city pages, so no other page moves. */
body.city-page.city-ed .footer {
    background: #0f141d;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}

/* ==========================================================================
   1. Masthead rule — breadcrumb sits above the first panel and shares its box
   ==========================================================================
   The fixed navbar is 106px tall and nothing else clears it on a city page:
   styles.css:361 `.breadcrumb { margin: 7.5rem auto 0 }` has specificity
   (0,1,0) and is beaten by styles.css:2448
   `nav[aria-label="Breadcrumb"] ol.breadcrumb { margin: 0 }` at (0,2,2).
   Restore the offset at (0,2,2)+1 rather than padding <main>.
   The nav carries the page gutter and the <ol> carries the panel padding, so
   the crumb text lines up exactly with the copy inside the hero panel below. */

body.city-ed nav[aria-label="Breadcrumb"] {
    padding-inline: var(--ce-gutter);
}

body.city-ed nav[aria-label="Breadcrumb"] ol.breadcrumb {
    width: min(1200px, 100%);
    margin: 8rem auto 1.1rem;
    padding-inline: var(--ce-pad);
    border-bottom: 0;
    font-size: 0.85rem;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ce-faint);
}

body.city-ed .breadcrumb a {
    color: var(--ce-dim);
}

body.city-ed .breadcrumb a:hover,
body.city-ed .breadcrumb a:focus-visible {
    color: var(--ce-cyan);
}

@media (max-width: 768px) {
    body.city-ed nav[aria-label="Breadcrumb"] ol.breadcrumb {
        margin-top: 6.5rem; /* matches the existing override at styles.css:2186 */
    }
}

/* ==========================================================================
   2. THE PANEL — the whole idea of v2
   Each section is a gutter-only wrapper; its existing .container is the card.
   Specificity is (0,3,1), which beats the .container rules in styles.css and
   the async sheets that load after this one.
   ========================================================================== */

body.city-ed .ce-hero,
body.city-ed .ce-section,
body.city-ed .services-in-city {
    position: relative;
    padding: 0 var(--ce-gutter);
    margin: 0 0 var(--ce-gap);
    border: 0;
    background: none;
}

body.city-ed .ce-hero > .container,
body.city-ed .ce-section > .container,
body.city-ed .services-in-city > .container {
    position: relative;
    max-width: 1200px;
    padding: var(--ce-pad);
    background: var(--ce-surface);
    border: 1px solid var(--ce-line);
    border-radius: var(--ce-r);
    box-shadow: var(--ce-lift);
}

/* the last panel needs air before the footer slab */
body.city-ed .ce-close {
    margin-bottom: clamp(2.5rem, 5vw, 4.25rem);
}

/* ==========================================================================
   3. Editorial primitives
   ONE small-caps label per panel (.ce-kicker) and nothing else shouts.
   Every other former micro-label is now sentence case at a readable size.
   ========================================================================== */

/* the single small-caps label, as a contained chip rather than a rule that
   stretches across the panel. styles.css:80 gives every h2 a clipped gradient
   fill, and .ce-kicker is an <h2> on the thesis panel — so background-clip and
   background-size must both be reset or the chip fill clips to the glyphs. */
body.city-ed .ce-kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1.15rem;
    padding: 0.45rem 0.85rem 0.45rem 0.7rem;
    border: 1px solid var(--ce-cyan-soft);
    border-radius: 999px;
    background: var(--ce-cyan-wash);
    background-size: auto;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    font-family: var(--ce-sans);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    line-height: 1;
    text-transform: uppercase;
    color: var(--ce-cyan);
    -webkit-text-fill-color: var(--ce-cyan);
    vertical-align: middle;
}

body.city-ed .ce-kicker::before {
    content: '';
    flex: none;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
}

body.city-ed .ce-kicker::after {
    content: none; /* v1's trailing gradient rule — removed, it was noise */
}

body.city-ed .ce-h2 {
    margin: 0 0 1rem;
    max-width: 22ch;
    font-family: var(--ce-serif);
    font-weight: 600;
    font-size: clamp(1.9rem, 3.1vw, 2.6rem);
    line-height: 1.1;
    letter-spacing: -0.015em;
    text-align: left;
    color: #fff;
    background: none;
    background-size: auto;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    -webkit-text-fill-color: #fff;
}

body.city-ed .ce-h2::after {
    content: none; /* neutralise the 60px underline bar some h2 rules add */
}

body.city-ed .ce-lede {
    max-width: 58ch;
    margin: 0;
    color: var(--ce-body);
    font-size: clamp(1.05rem, 0.35vw + 0.97rem, 1.16rem);
    line-height: 1.72;
}

body.city-ed .ce-lede strong {
    color: #fff;
    font-weight: 700;
}

/* ==========================================================================
   4. Hero panel
   Same grid, same slots. The panel carries a soft directional wash so the
   masthead reads as lit without a decorative overlay grid on the section.
   ========================================================================== */

body.city-ed .ce-hero > .container {
    background:
        radial-gradient(78% 120% at 82% 0%, rgba(63, 199, 211, 0.10), transparent 62%),
        radial-gradient(70% 100% at 0% 100%, rgba(163, 135, 243, 0.09), transparent 66%),
        var(--ce-surface);
}

body.city-ed .ce-hero-grid {
    display: grid;
    gap: clamp(2rem, 4vw, 3.25rem);
    align-items: center;
}

/* locator line — was 0.72rem/800/0.18em uppercase, now plain readable text */
body.city-ed .ce-eyebrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.6rem;
    margin: 0 0 1.35rem;
    font-size: 0.94rem;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1.5;
    text-transform: none;
    color: var(--ce-dim);
}

body.city-ed .ce-eyebrow svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--ce-cyan);
}

body.city-ed .ce-eyebrow b {
    font-weight: 600;
    color: var(--ce-strong);
}

body.city-ed .ce-eyebrow i {
    font-style: normal;
    color: rgba(255, 255, 255, 0.24);
}

/* always its own line, so the rule never breaks mid-separator */
body.city-ed .ce-eyebrow-zips {
    flex: 1 0 100%;
    padding-top: 0.35rem;
    color: var(--ce-faint);
    font-size: 0.88rem;
    font-variant-numeric: lining-nums tabular-nums;
}

body.city-ed .ce-h1 {
    margin: 0 0 1.35rem;
    max-width: 15ch;
    font-family: var(--ce-serif);
    font-weight: 600;
    font-size: clamp(2.35rem, 5.6vw, 4.1rem);
    line-height: 1.05;
    letter-spacing: -0.026em;
    color: #fff;
    background: none;
    background-size: auto;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    -webkit-text-fill-color: #fff;
    text-wrap: balance;
}

body.city-ed .ce-h1 em {
    font-style: italic;
    color: var(--ce-cyan);
    -webkit-text-fill-color: var(--ce-cyan);
}

/* v1 hung this off a cyan bar; the panel edge already does that job */
body.city-ed .ce-deck {
    max-width: 46ch;
    margin: 0 0 2rem;
    padding-left: 0;
    border-left: 0;
    color: var(--ce-body);
    font-size: clamp(1.06rem, 1.1vw, 1.2rem);
    line-height: 1.7;
}

body.city-ed .ce-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    margin-bottom: 0;
}

body.city-ed .ce-actions .btn {
    padding: 0.95rem 2rem;
    font-size: 1rem;
    letter-spacing: 0.01em;
}

body.city-ed .ce-actions .btn-secondary {
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--ce-line);
    color: #fff;
    padding: calc(0.95rem + 1px) 2rem;
}

body.city-ed .ce-actions .btn-secondary:hover {
    background: rgba(63, 199, 211, 0.14);
    border-color: rgba(63, 199, 211, 0.6);
    color: #fff;
    transform: translateY(-2px);
}

/* AA fix on the primary CTA. styles.css:627 sets
   .btn-primary { background: var(--gradient-primary); color: white }, which
   measures 2.03:1 against #3FC7D3 and 2.60:1 against #36b0bb — a hard AA fail
   at 16px/600 with no large-text exemption. #06222a measures 8.13:1 at the
   light end of the gradient and 6.37:1 at the dark end, so it passes across
   the whole sweep. The :hover selector is MANDATORY: styles.css:633 restates
   `.btn-primary:hover { color: white }` at (0,2,0). Keep this scoped to
   .ce-actions — widening it would change every other page on the site. */
body.city-ed .ce-actions .btn-primary,
body.city-ed .ce-actions .btn-primary:hover,
body.city-ed .ce-actions .btn-primary:focus-visible {
    color: #06222a;
}

/* --- Fact rail: the fixed trust contract, identical on all 22 pages.
   Now a nested strip card inside the hero panel. The 1px grid gap over a dark
   backing draws the dividers, so no per-cell border logic and no odd/even
   padding gymnastics are needed. --- */
body.city-ed .ce-facts {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px;
    margin: clamp(1.5rem, 3vw, 2.5rem) 0 0;
    padding: 1px;
    background: rgba(0, 0, 0, 0.45); /* shows through the 1px gaps as the seam */
    border: 1px solid var(--ce-line);
    border-radius: var(--ce-r-sm);
    overflow: hidden;
}

body.city-ed .ce-facts > div {
    padding: 0.95rem 1.15rem;
    background: var(--ce-raised);
    border: 0;
}

/* five cells in a two-up grid leaves a hole; let the last one span */
body.city-ed .ce-facts > div:last-child {
    grid-column: 1 / -1;
}

body.city-ed .ce-facts dt {
    margin-bottom: 0.35rem;
    font-size: 0.79rem;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ce-faint);
}

body.city-ed .ce-facts dd {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1.45;
    color: var(--ce-strong);
}

body.city-ed .ce-facts dd a {
    color: inherit;
    border-bottom: 1px solid rgba(63, 199, 211, 0.45);
}

body.city-ed .ce-facts dd a:hover,
body.city-ed .ce-facts dd a:focus-visible {
    color: var(--ce-cyan);
}

body.city-ed .ce-star {
    width: 13px;
    height: 13px;
    vertical-align: -1px;
    color: var(--secondary-color);
    margin-right: 0.2rem;
}

/* --- art plate (shared frame; the artwork itself is per-city) --- */
body.city-ed .ce-plate {
    position: relative;
    justify-self: center;
    width: 100%;
    max-width: 440px;
    contain: paint; /* keep the blurred glow off the hero's repaint area */
}

body.city-ed .ce-plate::before {
    content: '';
    position: absolute;
    inset: 8% 4% 12%;
    border-radius: 999px 999px 24px 24px;
    background: radial-gradient(closest-side, rgba(63, 199, 211, 0.16), transparent 78%);
    filter: blur(6px);
    pointer-events: none;
}

body.city-ed .ce-plate svg {
    position: relative;
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

/* ==========================================================================
   5. Thesis panel
   A deeper surface with a violet-leaning edge marks it as the page's one
   pull-quote. v1's pinstripe overlay is gone.
   ========================================================================== */

body.city-ed .ce-thesis > .container {
    background:
        radial-gradient(110% 150% at 100% 0%, rgba(163, 135, 243, 0.11), transparent 60%),
        var(--ce-thesis-surface);
    border-color: rgba(163, 135, 243, 0.22);
}

body.city-ed .ce-quote {
    margin: 0;
}

/* measure lives on the <p>, not the <blockquote> — ch resolves against the
   element's own font, and only the <p> carries the display serif */
body.city-ed .ce-quote p {
    margin: 0;
    max-width: 30ch;
    font-family: var(--ce-serif);
    font-weight: 500;
    font-size: clamp(1.6rem, 3.9vw, 2.9rem);
    line-height: 1.2;
    letter-spacing: -0.018em;
    color: #fff;
    text-wrap: pretty;
}

body.city-ed .ce-quote strong {
    font-weight: 500;
    font-style: italic;
    color: var(--ce-cyan);
}

/* was a 0.7rem/800/0.2em uppercase label behind a violet bar; now a plain
   serif attribution, which is one fewer shouting element on the page */
body.city-ed .ce-quote footer {
    display: block;
    margin-top: 1.75rem;
    font-family: var(--ce-serif);
    font-style: italic;
    font-size: 1.02rem;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1.5;
    text-transform: none;
    color: var(--ce-faint);
}

body.city-ed .ce-quote footer::before {
    content: '\2014\00a0';
    color: var(--ce-violet);
}

/* ==========================================================================
   6. Method panel — three numbered cards (+ optional text-free diagram)
   ========================================================================== */

/* The method panel is a STACK, never a two-track row: the three cards always
   take the full panel width and the cutaway sits on its own row beneath them.

   v2 originally reserved a fixed 300px side track for .ce-figure at >=900px
   while .ce-cols stayed 3-up from 620px. The two compounded: at a 1024px
   viewport each card was left ~124px of text — 13-15 characters a line,
   10-17 line paragraphs, <h3> broken over 3-4 lines — while 122-297px of
   space sat empty under the shorter figure column on all 21 pages that carry
   a figure. It also inverted at the breakpoint (205px of measure at 879px
   collapsing to 96px at 900px), so widening the window made the section
   harder to read, and mobile out-read every desktop width. houston.html is
   the control: it ships no .ce-method-grid, and its cards have always
   measured 24-27 characters a line at 1024px. This makes the other 21 match.

   The row gap is deliberately larger than the panel's other gaps because
   .ce-figure::before bleeds 1.75rem above the figure box; a 2rem gap would
   leave 4px of air between that backdrop and the cards above it.
   The top margin restates what a bare .ce-cols already gets, so the heading
   clears the cards by the same amount on all 22 pages. */
body.city-ed .ce-method-grid {
    display: grid;
    gap: clamp(3.25rem, 5vw, 4.25rem);
    margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
    align-items: start;
}

body.city-ed .ce-cols {
    display: grid;
    gap: clamp(0.75rem, 1.6vw, 1rem);
    margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
}

body.city-ed .ce-method-grid .ce-cols {
    margin-top: 0;
}

/* the column is now a card: numeral chip and icon share the header row,
   heading and body stack beneath. Placement is done with grid so the source
   order (num, icon, h3, p) needs no HTML change. */
body.city-ed .ce-col {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-content: start;
    gap: 0 0.75rem;
    padding: var(--ce-pad-sm);
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
}

body.city-ed .ce-col + .ce-col {
    margin-top: 0;
}

body.city-ed .ce-num {
    grid-column: 1;
    grid-row: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.15rem;
    height: 2.15rem;
    margin: 0;
    border: 1px solid var(--ce-cyan-soft);
    border-radius: 9px;
    background: var(--ce-cyan-wash);
    font-family: var(--ce-serif);
    font-size: 0.95rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0;
    color: var(--ce-cyan);
    -webkit-text-stroke: 0;
    font-variant-numeric: lining-nums tabular-nums;
}

body.city-ed .ce-col-icon {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    align-self: center;
    width: 26px;
    height: 26px;
    color: rgba(95, 227, 232, 0.55);
}

body.city-ed .ce-col h3 {
    grid-column: 1 / -1;
    grid-row: 2;
    margin: 1.15rem 0 0.55rem;
    font-family: var(--ce-serif);
    font-size: 1.28rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1.25;
    color: #fff;
}

/* The measure cap is live only while the cards run one-up — below 900px, and
   only once the panel is wide enough to exceed it (roughly a 700px viewport
   up). At 3-up the track itself is always the narrower constraint (~300px at
   1440px), so this never binds there. It was 42ch while the figure track was
   stealing the row: dead code, because the column never reached half of it. */
body.city-ed .ce-col p {
    grid-column: 1 / -1;
    grid-row: 3;
    margin: 0;
    max-width: 60ch;
    color: var(--ce-body);
    font-size: 1.01rem;
    line-height: 1.72;
}

/* --- cutaway figure: SVG carries NO text; every label is HTML.
   The .ce-figure box must NOT gain padding — the inline `top:` percentages on
   .ce-callouts li are measured against this box, and padding would shift the
   leader lines on all 21 pages. The backdrop is therefore a pseudo-element
   with a negative inset, which paints outside the box without resizing it. --- */
/* The bottom margin matches the ::before overhang below. The figure is now
   the last thing in the method panel at every width, and without it the
   backdrop would run to within a few px of the panel's own padding edge.
   Margin is safe here where padding is not: it moves the box without
   resizing it, so the inline `top:` percentages still resolve identically. */
body.city-ed .ce-figure {
    position: relative;
    isolation: isolate;
    width: 100%;
    max-width: 320px;
    margin: 0 auto 1.75rem;
    justify-self: center;
}

body.city-ed .ce-figure::before {
    content: '';
    position: absolute;
    inset: -1.75rem -1.5rem;
    z-index: -1;
    border-radius: var(--ce-r-sm);
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    pointer-events: none;
}

body.city-ed .ce-figure svg {
    display: block;
    width: 100%;
    height: auto;
}

body.city-ed .ce-callouts {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* was 0.68rem/800/0.14em uppercase — now plain, legible, sentence case */
body.city-ed .ce-callouts li {
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.35;
    text-transform: none;
    color: var(--ce-strong);
}

@media (min-width: 620px) {
    body.city-ed .ce-callouts {
        position: absolute;
        inset: 0;
        pointer-events: none;
    }

    body.city-ed .ce-callouts li {
        position: absolute;
        left: 56%;
        width: 44%;
        padding-left: 0.5rem;
    }

    body.city-ed .ce-callouts li::before {
        content: '';
        position: absolute;
        top: 0.55em;
        right: 100%;
        width: var(--lead, 1.5rem);
        height: 1px;
        background: rgba(95, 227, 232, 0.5);
    }
}

/* Below 620px the leader lines have nowhere to go — plain 2x2 index instead.
   The size cap sits on the DRAWING, not the BOX: capping .ce-figure itself at
   220px would trap the 2-column callout grid inside that 220px and leave each
   label roughly 100px of measure.
   CRITICAL: the `svg { max-width: 230px }` rule must live ONLY inside this
   query. Above 620px .ce-callouts is `position:absolute; inset:0` and every
   page's leader-line anchors are inline percentages measured against
   .ce-figure, so shrinking the svg at desktop would decouple the lines from
   the drawing on all 21 pages that carry a figure. */
@media (max-width: 619px) {
    body.city-ed .ce-figure {
        max-width: 24rem;
        margin-bottom: 1.25rem; /* tracks the smaller ::before inset below */
    }

    body.city-ed .ce-figure svg {
        max-width: 230px;
        margin: 0 auto;
    }

    body.city-ed .ce-figure::before {
        inset: -1.25rem -1rem;
    }

    body.city-ed .ce-callouts {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.85rem 1.25rem;
        margin: 1.75rem auto 0;
    }

    body.city-ed .ce-callouts li {
        padding-left: 0.65rem;
        border-left: 1px solid rgba(95, 227, 232, 0.5);
    }
}

/* ==========================================================================
   7. Rates panel
   Bands render only when every figure is owner-confirmed; otherwise the
   section ships the single sourced $149 line and the .ce-scale rules sit idle.
   ========================================================================== */

/* the pricing panel gets a faint cyan lean so it reads as its own moment
   without a second heading style or an extra label */
body.city-ed .ce-rates > .container {
    background:
        radial-gradient(80% 110% at 100% 0%, rgba(63, 199, 211, 0.07), transparent 64%),
        var(--ce-surface);
}

body.city-ed .ce-scale {
    display: grid;
    gap: clamp(0.75rem, 1.6vw, 1rem);
    margin: clamp(1.75rem, 3.5vw, 2.5rem) 0 0;
    padding: 0;
    list-style: none;
}

body.city-ed .ce-rate {
    padding: var(--ce-pad-sm);
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
}

body.city-ed .ce-rate-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.35rem 1.5rem;
    margin-bottom: 1.1rem;
}

body.city-ed .ce-rate h3 {
    margin: 0;
    font-family: var(--ce-serif);
    font-size: 1.28rem;
    font-weight: 600;
    color: #fff;
    line-height: 1.25;
}

body.city-ed .ce-rate-sub {
    margin: 0.25rem 0 0;
    flex: 1 1 12rem;
    color: var(--ce-faint);
    font-size: 0.9rem;
    letter-spacing: 0;
}

body.city-ed .ce-rate-figure {
    margin: 0;
    font-family: var(--ce-serif);
    font-size: clamp(1.35rem, 2.4vw, 1.85rem);
    font-weight: 600;
    letter-spacing: -0.015em;
    color: var(--ce-cyan);
    white-space: nowrap;
    font-variant-numeric: lining-nums tabular-nums;
}

body.city-ed .ce-rate-figure i {
    font-style: normal;
    color: rgba(255, 255, 255, 0.28);
    padding: 0 0.3rem;
}

body.city-ed .ce-rate-track {
    position: relative;
    height: 10px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.35);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.5);
}

body.city-ed .ce-rate-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--from);
    right: calc(100% - var(--to));
    min-width: 34px; /* keep the two 12px end handles from merging into a blob */
    border-radius: 999px;
    background: linear-gradient(90deg, var(--ce-cyan), var(--ce-violet));
}

body.city-ed .ce-rate-fill::before,
body.city-ed .ce-rate-fill::after {
    content: '';
    position: absolute;
    top: 50%;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    transform: translateY(-50%);
    background: var(--ce-raised);
    border: 2px solid currentColor;
}

body.city-ed .ce-rate-fill::before {
    left: -1px;
    color: var(--ce-cyan);
}

body.city-ed .ce-rate-fill::after {
    right: -1px;
    color: var(--ce-violet);
}

/* grid, not flex: ticks must land on true 0/25/50/75/100% of the track box */
body.city-ed .ce-axis {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    text-align: center;
    margin: 0.9rem 0 0;
    padding: 0.7rem 0 0;
    list-style: none;
    font-size: 0.78rem;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--ce-faint);
    font-variant-numeric: lining-nums tabular-nums;
    border-top: 1px solid var(--ce-hair);
}

body.city-ed .ce-axis li:first-child {
    text-align: left;
}

body.city-ed .ce-axis li:last-child {
    text-align: right;
}

/* fine print gets its own inset slab rather than floating as loose grey text */
body.city-ed .ce-note {
    margin: clamp(1.5rem, 3vw, 2rem) 0 0;
    padding: 0.95rem 1.15rem;
    max-width: 64ch;
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
    font-size: 0.94rem;
    line-height: 1.68;
    color: var(--ce-dim);
}

body.city-ed .ce-note a {
    color: var(--ce-cyan);
    border-bottom: 1px solid rgba(95, 227, 232, 0.4);
}

/* ==========================================================================
   8. Coverage panel — each definition list is its own nested card
   ========================================================================== */

body.city-ed .ce-index-grid {
    display: grid;
    gap: clamp(0.75rem, 1.6vw, 1rem);
    margin-top: clamp(1.75rem, 3.5vw, 2.5rem);
    align-items: start;
}

body.city-ed .ce-index {
    padding: var(--ce-pad-sm);
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
}

/* was 0.65rem/800/0.19em uppercase — now a real subhead */
body.city-ed .ce-index dt {
    margin-bottom: 0.5rem;
    font-size: 0.84rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ce-cyan);
}

body.city-ed .ce-index dd {
    margin: 0 0 1.35rem;
    padding-bottom: 1.35rem;
    border-bottom: 1px solid var(--ce-hair);
    color: var(--ce-body);
    font-size: 1.02rem;
    line-height: 1.68;
}

body.city-ed .ce-index dd:last-of-type {
    margin-bottom: 0;
    padding-bottom: 0;
    border-bottom: 0;
}

body.city-ed .ce-ziptiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
    gap: 0.5rem;
    list-style: none;
    padding: 0;
    margin: 0;
}

body.city-ed .ce-ziptiles li {
    padding: 0.65rem 0.5rem;
    border: 1px solid rgba(95, 227, 232, 0.2);
    border-radius: 10px;
    background: var(--ce-cyan-wash);
    font-family: var(--ce-serif);
    font-size: 1.05rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    line-height: 1.2;
    text-align: center;
    color: var(--ce-strong);
    font-variant-numeric: lining-nums tabular-nums;
}

body.city-ed .ce-near {
    display: flex;
    flex-wrap: wrap;
    gap: 0.55rem;
    list-style: none;
    padding: 0;
    margin: 0;
}

body.city-ed .ce-near a {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.55rem 0.95rem;
    border: 1px solid var(--ce-line);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--ce-strong);
    font-size: 0.92rem;
    font-weight: 600;
    transition: background 0.2s ease, border-color 0.2s ease;
}

body.city-ed .ce-near a::after {
    content: '';
    width: 5px;
    height: 5px;
    border-top: 1px solid currentColor;
    border-right: 1px solid currentColor;
    transform: rotate(45deg);
    opacity: 0.6;
}

body.city-ed .ce-near a:hover,
body.city-ed .ce-near a:focus-visible {
    border-color: rgba(95, 227, 232, 0.6);
    background: rgba(63, 199, 211, 0.14);
    color: #fff;
}

/* ==========================================================================
   9. Services hub — restyles the existing .services-in-city markup contract
   ========================================================================== */

body.city-ed .services-in-city .services-in-city-sub {
    max-width: 52ch;
    margin: 0 0 clamp(1.75rem, 3.5vw, 2.5rem);
    text-align: left;
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--ce-body);
}

body.city-ed .services-in-city-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(0.65rem, 1.4vw, 0.9rem);
    border: 0;
}

body.city-ed .services-in-city-card {
    display: block;
    padding: var(--ce-pad-sm);
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
    transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

body.city-ed .services-in-city-card:hover,
body.city-ed .services-in-city-card:focus-visible {
    transform: translateY(-2px);
    box-shadow: none;
    background: var(--ce-hover);
    border-color: rgba(95, 227, 232, 0.4);
    padding-left: var(--ce-pad-sm);
}

body.city-ed .services-in-city-card h3 {
    margin: 0 0 0.3rem;
    min-width: 0;
    font-family: var(--ce-serif);
    font-size: 1.14rem;
    font-weight: 600;
    letter-spacing: -0.005em;
    line-height: 1.3;
    color: #fff;
    background: none;
    background-size: auto;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    -webkit-text-fill-color: #fff;
}

body.city-ed .services-in-city-card:hover h3,
body.city-ed .services-in-city-card:focus-visible h3 {
    color: var(--ce-cyan);
    -webkit-text-fill-color: var(--ce-cyan);
}

body.city-ed .services-in-city-card p {
    margin: 0;
    font-size: 0.95rem;
    line-height: 1.6;
    color: var(--ce-dim);
}

/* ==========================================================================
   10. FAQ panel — every question is its own card
   ========================================================================== */

body.city-ed .ce-faq-list {
    display: grid;
    gap: 0.7rem;
    margin: clamp(1.75rem, 3.5vw, 2.5rem) 0 0;
    border: 0;
}

body.city-ed .ce-faq-list details {
    background: var(--ce-raised);
    border: 1px solid var(--ce-hair);
    border-radius: var(--ce-r-sm);
}

body.city-ed .ce-faq-list details[open] {
    background: var(--ce-hover);
    border-color: rgba(95, 227, 232, 0.26);
}

body.city-ed .ce-faq-list summary {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1.25rem;
    padding: 1.15rem var(--ce-pad-sm);
    cursor: pointer;
    list-style: none;
    font-family: var(--ce-serif);
    font-size: clamp(1.06rem, 1.6vw, 1.24rem);
    font-weight: 600;
    line-height: 1.4;
    color: #fff;
}

body.city-ed .ce-faq-list summary::-webkit-details-marker {
    display: none;
}

body.city-ed .ce-faq-list summary::after {
    content: '';
    flex: none;
    width: 12px;
    height: 12px;
    margin-top: 0.45em;
    border-right: 1.5px solid var(--ce-cyan);
    border-bottom: 1.5px solid var(--ce-cyan);
    transform: rotate(45deg);
    transition: transform 0.3s ease;
}

body.city-ed .ce-faq-list details[open] summary::after {
    transform: rotate(-135deg);
}

body.city-ed .ce-faq-list summary:hover {
    color: var(--ce-cyan);
}

/* <summary> is a keyboard-operable control and needs a visible focus ring.
   The offset is negative on purpose: a positive offset would push the ring
   outside the card's rounded border and clip against the neighbouring row. */
body.city-ed .ce-faq-list summary:focus-visible {
    outline: 3px solid rgba(95, 227, 232, 0.6);
    outline-offset: -3px;
    border-radius: var(--ce-r-sm);
}

body.city-ed .ce-faq-list p {
    margin: 0;
    max-width: 68ch;
    padding: 0 var(--ce-pad-sm) 1.35rem;
    border-left: 0;
    color: var(--ce-body);
    font-size: 1.01rem;
    line-height: 1.75;
}

/* ==========================================================================
   11. Close panel — the one place the accent is allowed to carry the surface
   ========================================================================== */

body.city-ed .ce-close > .container {
    text-align: center;
    background:
        radial-gradient(90% 130% at 50% 0%, rgba(63, 199, 211, 0.13), transparent 62%),
        radial-gradient(90% 120% at 50% 100%, rgba(163, 135, 243, 0.13), transparent 66%),
        var(--ce-surface);
    border-color: rgba(95, 227, 232, 0.28);
}

body.city-ed .ce-close .ce-h2 {
    max-width: 18ch;
    margin-inline: auto;
    text-align: center;
    font-size: clamp(2rem, 4vw, 3.1rem);
}

body.city-ed .ce-close .ce-lede {
    margin: 0 auto;
}

body.city-ed .ce-close .ce-actions {
    justify-content: center;
    margin: 2.25rem 0 0;
}

body.city-ed .ce-close .btn-white {
    padding: 0.95rem 2rem;
    font-weight: 700;
}

/* .btn sets border: none, so the outline variant must restate it */
body.city-ed .ce-close .btn-outline-white {
    padding: calc(0.95rem - 2px) 2rem;
    background: transparent;
    border: 2px solid rgba(255, 255, 255, 0.42);
    color: #fff;
}

body.city-ed .ce-close .btn-outline-white:hover {
    background: #fff;
    color: var(--ce-ground);
}

body.city-ed .ce-hours {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.4rem 0.9rem;
    margin: 2.25rem auto 0;
    padding-top: 1.6rem;
    border-top: 1px solid var(--ce-line);
    max-width: 46rem;
    font-size: 0.92rem;
    line-height: 1.6;
    letter-spacing: 0;
    color: var(--ce-dim);
}

body.city-ed .ce-hours i {
    font-style: normal;
    color: rgba(255, 255, 255, 0.24);
}

body.city-ed .ce-hours a {
    color: var(--ce-strong);
    border-bottom: 1px solid rgba(95, 227, 232, 0.4);
}

body.city-ed .ce-hours a:hover,
body.city-ed .ce-hours a:focus-visible {
    color: var(--ce-cyan);
}

/* ==========================================================================
   12. Responsive
   ========================================================================== */

@media (min-width: 620px) {
    body.city-ed .ce-rate-head {
        flex-wrap: nowrap;
    }

    body.city-ed .services-in-city-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 900px) {
    body.city-ed .ce-hero-grid {
        grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
        column-gap: clamp(2.5rem, 5vw, 4.5rem);
        row-gap: 0;
    }

    body.city-ed .ce-facts {
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }

    body.city-ed .ce-facts > div:last-child {
        grid-column: auto;
    }

    /* Three-up only once the full-width panel can actually carry it. At 900px
       each card gets ~210px of text (about 24 characters a line) and it only
       improves from there — ~240px at 1024px, ~300px at 1440px. The old 620px
       trigger produced 137px at its own breakpoint, narrower than the same
       card gets on a phone. Below 900px the cards run one-up and .ce-col p's
       measure cap does the work instead. */
    body.city-ed .ce-cols {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    body.city-ed .ce-index-grid {
        grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
    }

    body.city-ed .ce-quote {
        margin-left: clamp(0rem, 4vw, 5rem);
    }
}

@media (max-width: 899px) {
    body.city-ed .ce-plate {
        max-width: 320px;
        margin-top: 0.5rem;
    }
}

@media (max-width: 619px) {
    body.city-ed .ce-facts {
        grid-template-columns: 1fr;
    }

    body.city-ed .ce-facts > div,
    body.city-ed .ce-facts > div:last-child {
        grid-column: 1;
        padding: 0.9rem 1rem;
    }

    body.city-ed .ce-actions .btn {
        flex: 1 1 100%;
    }

    body.city-ed .ce-axis {
        font-size: 0.72rem;
    }

    /* pin label and figure to their own tracks so a long label can never
       push the price onto a second row */
    body.city-ed .ce-rate-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: baseline;
        gap: 0.15rem 0.75rem;
    }

    body.city-ed .ce-rate-head > div {
        grid-column: 1;
        grid-row: 1;
    }

    body.city-ed .ce-rate-figure {
        grid-column: 2;
        grid-row: 1;
        margin-top: 0;
    }
}

@media (max-width: 480px) {
    body.city-ed .ce-plate {
        max-width: 250px;
    }
}

/* ==========================================================================
   13. Scroll-driven reveal — progressive enhancement only.
   Content is fully visible where animation-timeline is unsupported, so there
   is no JS dependency and no risk of a blank section.
   ========================================================================== */

@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        body.city-ed .ce-rise {
            /* longhands only — the `animation` shorthand resets animation-timeline */
            animation-name: ce-rise-in;
            animation-duration: auto;
            animation-timing-function: linear;
            animation-fill-mode: both;
            animation-timeline: view();
            animation-range: entry 2% cover 20%;
        }
    }
}

@keyframes ce-rise-in {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   14. Windows High Contrast
   ========================================================================== */

@media (forced-colors: active) {
    body.city-ed .ce-hero > .container,
    body.city-ed .ce-section > .container,
    body.city-ed .services-in-city > .container,
    body.city-ed .ce-col,
    body.city-ed .ce-index,
    body.city-ed .ce-rate,
    body.city-ed .ce-facts,
    body.city-ed .ce-note,
    body.city-ed .ce-faq-list details,
    body.city-ed .services-in-city-card {
        background: Canvas;
        border: 1px solid CanvasText;
        box-shadow: none;
    }

    body.city-ed .ce-h1,
    body.city-ed .ce-h1 em,
    body.city-ed .ce-h2,
    body.city-ed .ce-kicker,
    body.city-ed .ce-quote p,
    body.city-ed .ce-quote strong,
    body.city-ed .services-in-city-card h3 {
        background: none !important;
        -webkit-text-fill-color: CanvasText !important;
        color: CanvasText !important;
    }

    body.city-ed .ce-num,
    body.city-ed .ce-ziptiles li,
    body.city-ed .ce-near a {
        background: Canvas;
        border: 1px solid CanvasText;
        color: CanvasText;
        -webkit-text-stroke: 0;
    }

    body.city-ed .ce-figure::before {
        display: none;
    }

    body.city-ed .ce-rate-fill {
        background: Highlight;
        forced-color-adjust: none;
    }
}
