/* Solve Canada -- national hub stylesheet (solvecanada.ca).
   Ported unchanged from the approved static prototype at
   /Users/ahmed/Downloads/PROJECTS/solvecanada/css/site.css -- see
   docs/media/solve-canada-map/DESIGN-SYSTEM.md. Plain CSS on purpose:
   arbitrary Tailwind classes would need a rebuild anyway (see playbook.css,
   pulse.css for the same pattern in this app). Self-hosted fonts, no
   external requests.

   Font paths are flat relative to Propshaft's asset load path (no "../" --
   Propshaft's CssAssetUrls compiler resolves url() relative to this file's
   own logical path and rewrites it to the digested path; confirmed with a
   smoke test before the rest of this file was ported). Map/city imagery is
   rendered via <img> tags with image_path in the views, not CSS url().

   SCOPING (added after a leak was caught in review): Rails' Propshaft
   `stylesheet_link_tag :app` loads every stylesheet in this directory on
   EVERY page in the app (application.css, blog.css, playbook.css, pulse.css,
   this file, etc all load together on every request -- this is intentional,
   existing app behaviour, not something to "fix" here). Every OTHER
   stylesheet in this app scopes its rules under a root class so they can
   coexist. This file originally did not: it had unscoped `*`, `html`,
   `body`, `h1,h2,h3`, `p`, `a`, and (worse) a generic `.container` rule that
   collided with Tailwind's own `.container` utility class used all over the
   rest of the app. Every rule below is scoped under `.solve-canada`, the
   class on <body> in layouts/solve_canada.html.erb, so nothing here can ever
   apply outside that layout. See test/... for the regression test that
   guards this file stays scoped. */

/* Instrument Serif's woff2 stays in the repo (cheap to keep, trivial to
   revert to) but is no longer referenced by --font-display below -- see
   Zodiak, next rule. Do not delete the font file or this comment without
   checking with Ahmed first. */
@font-face{
  font-family:"Instrument Serif";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/InstrumentSerif-400-5e24a7c0.woff2") format("woff2");
}
/* Gambarino's woff2 also stays in the repo, unreferenced (2026-07-12 swap
   to Zodiak, Ahmed's call) -- same "cheap to keep, one line to revert"
   reasoning as Instrument Serif above. Do not delete the font file or this
   comment without checking with Ahmed first. */
@font-face{
  font-family:"Gambarino";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/Gambarino-400-fcc85469.woff2") format("woff2");
}
/* Display face, self-hosted (2026-07-12 swap from Gambarino, Ahmed's call).
   Zodiak (Fontshare), ITF Free Font Licence -- commercial use permitted,
   self-hosting permitted, resale/redistribution of the font file itself is
   not (we are not doing that). Single weight (400) by design: display/
   headline use only, never body copy. Checked for the same defect
   Instrument Serif had (numeral "1" reading as lowercase "l", which shipped
   once as "311" -> "3ll"): Zodiak's "1" carries its own flag/serif and is
   visually distinct from "l" and "I" at both display and body-adjacent
   sizes -- verified by screenshot, so no sans-fallback hack is required for
   its numerals. */
@font-face{
  font-family:"Zodiak";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/Zodiak-400-7b9215ef.woff2") format("woff2");
}
/* Bold cut, same family, separate file (Fontshare ships Zodiak as static
   weights, not a variable font -- 400 and 700 are two different files).
   Used for every headline (h1-h3, the vision headline, the hub-diagram
   root) after Ahmed's note that the display face "reads thin" at 400 --
   never for body copy. */
@font-face{
  font-family:"Zodiak";
  font-style:normal;font-weight:700;
  font-display:block;
  src:url("/assets/Zodiak-700-7ebaa8ef.woff2") format("woff2");
}
/* Lexend's woff2 stays in the repo but most of the page no longer
   references it (2026-07-12 swap to Libre Baskerville, Ahmed's call -- see
   --font-body below). A handful of small-UI selectors still point at this
   family on purpose: see the comment on body.solve-canada below for exactly
   which ones and why. Do not delete the font file. */
@font-face{
  font-family:"Lexend";
  font-style:normal;font-weight:100 900;
  font-display:block;
  src:url("/assets/Lexend-var-80258e9a.woff2") format("woff2");
}
/* Body/UI face, self-hosted (2026-07-12 swap from Lexend, Ahmed's call).
   Libre Baskerville (Impallari Type via Google Fonts), SIL Open Font
   Licence -- commercial use and self-hosting permitted. Instantiated as
   static 400/700/italic woff2s with fonttools from Google's variable
   source (the upstream family ships a wght-variable regular + a static
   italic; three static cuts here match what every other @font-face block
   in this file already assumes: one file per style/weight, no variable
   axis math in the CSS). */
@font-face{
  font-family:"Libre Baskerville";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/LibreBaskerville-400-5f9b9e8d.woff2") format("woff2");
}
@font-face{
  font-family:"Libre Baskerville";
  font-style:italic;font-weight:400;
  font-display:block;
  src:url("/assets/LibreBaskerville-Italic-400-faee9a18.woff2") format("woff2");
}
@font-face{
  font-family:"Libre Baskerville";
  font-style:normal;font-weight:700;
  font-display:block;
  src:url("/assets/LibreBaskerville-700-46717375.woff2") format("woff2");
}
/* Proxima Nova removed 2026-07-12. It is a commercial face (Mark Simonson
   Studio) and an @font-face here would serve the raw .otf from /assets to
   anyone who asks, which is redistribution. Nothing rendered it: the display
   face is Sentient and the body face is General Sans, both Fontshare, both
   free for commercial use. Do not re-add it without a purchased web licence. */
@font-face{
  font-family:"Sentient-Regular";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/Sentient-Regular-a07198fa.woff") format("woff");
}
@font-face{
  font-family:"Sentient-Medium";
  font-style:normal;font-weight:500;
  font-display:block;
  src:url("/assets/Sentient-Medium-177f81b4.woff") format("woff");
}
@font-face{
  font-family:"GeneralSans-Light";
  font-style:normal;font-weight:100;
  font-display:block;
  src:url("/assets/GeneralSans-Light-41904571.woff2") format("woff2");
}
@font-face{
  font-family:"GeneralSans-Medium";
  font-style:normal;font-weight:500;
  font-display:block;
  src:url("/assets/GeneralSans-Medium-5447476b.woff2") format("woff2");
}
@font-face{
  font-family:"GeneralSans-Regular";
  font-style:normal;font-weight:400;
  font-display:block;
  src:url("/assets/GeneralSans-Regular-13007e8c.woff2") format("woff2");
}

.solve-canada{
  --teal:#2A4853;
  --teal-deep:#1c333c;
  --cream:#F3EDDF;
  --cream-dim:#b7b2a2;
  --coral:#F35A52;
  --ink:#111111;
  --white:#FFFFFF;
  --font-display:"Sentient-Regular","Hoefler Text",Garamond,Georgia,serif;

  --font-body-regular:"GeneralSans-Regular","Hoefler Text",Garamond,Georgia,serif;
  /* Body/UI face (2026-07-12 swap from Lexend to Libre Baskerville). One
     swappable slot, same pattern as --font-display above: to revert,
     change this one line back to var(--font-sans). */
  --font-body:"GeneralSans-Light", "Libre Baskerville","Hoefler Text",Georgia,serif;
  /* Lexend stays wired here for the small set of UI-chrome selectors below
     that read badly as a small tracked serif (see the body.solve-canada
     comment) -- everything else now reads --font-body instead. */
  --font-sans:"Lexend",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;
  --measure:38rem;
  /* One shared reading column for every text section (statement, problem,
     vision, FAQ, founder, contact) so the page reads as one measure instead
     of a set of differently-sized columns (Ahmed's 2026-07-12 note: the
     statement section was a "thin ribbon" at 46rem/736px on a wide screen).
     Every element that uses this sits inside .container/.section or
     .inquiry-inner, which already supply the side gutter via padding, so a
     plain max-width is enough: as a block-level max-width it is a ceiling,
     never a fixed width, so it already shrinks to fit a phone with no
     separate mobile override (the same pattern every other max-width rule
     in this file already relies on). */
  --measure-wide:900px;

  /* ----------------------------------------------------------------------
     TYPE SCALE (2026-07-12, revised same day after a second pass of
     feedback). Ahmed had been hand-editing font-size/weight/letter-spacing
     at individual selectors, so sizes drifted (22px vs 20px vs 21px body
     copy that all meant "paragraph", 11px vs 13px vs 14.5px fine print
     that all meant "caption"). Every text rule below reads its size from
     one of these steps -- to change the scale, change it here once. Two
     sections keep their own numbers on purpose: the hero (.sc-*) is ported
     unchanged from the approved artifact and has its own animated intro/
     settle sizing, and the vision headline uses a dedicated top step
     (--step-display) reserved for that one moment.

     --step-body is now the ONE paragraph size for every prose section
     (statement, problem, city panels, doors, vision, founder, FAQ,
     contact) -- Ahmed: "all font size for body should be similar size."
     --step-body-lg no longer means "body text"; it is kept only for the
     small bold sans sub-headings on the door cards, which are labels, not
     paragraph copy. --step-ui is UI chrome only (form inputs/labels), not
     prose, after FAQ answers moved to --step-body.

     RE-TUNED 2026-07-12 for the Lexend -> Libre Baskerville swap. Measured
     with fonttools against both self-hosted files: the two faces share
     almost the same x-height (0.53em vs 0.525em, the dimension that
     dominates how big lowercase-heavy prose *looks*), so --step-body did
     not need to shrink to fix "looks bigger." What actually changes is
     average character advance width -- Baskerville's lowercase runs ~7%
     wider (0.587em vs 0.549em) -- which eats into characters-per-line at a
     fixed measure. --step-body comes down 1px at both ends of its clamp to
     hold the 900px measure in the 60-80 cpl target (verified in-browser
     with canvas.measureText against the real rendered paragraph copy, see
     the swap notes in this repo's PR/commit history). */
  --step-eyebrow:12px;      /* every .eyebrow, uppercase, .2em tracking */
  --step-fine:13px;         /* captions: photo credit, fallback text */
  --step-micro:11px;        /* smallest fine print: contact card's WHERE line + bottom bar */
  --step-ui:16px;           /* form inputs/labels only */
  --step-body:clamp(16px,1.2vw,18px);   /* the one paragraph-copy size, every section */
  --step-body-lg:clamp(19px,1.6vw,22px);/* door-card sub-heading labels only, NOT body copy */
  --step-lede:clamp(23px,2.8vw,34px);   /* the one big serif line in a section */
  --step-h3:clamp(24px,3vw,24px);       /* sub-headings */
  --step-h3-lg:clamp(34px,5vw,45px);    /* city-panel names, the contact card headline */
  --step-h2-sm:clamp(30px,4.2vw,35px);
  --step-h2:clamp(30px,4.2vw,47px);     /* section headlines */
  /* Shrunk twice on 2026-07-12: first because it "ate the whole screen",
     then again because the vision headline still left no room to see the
     new hub-diagram without scrolling. Also feeds the (currently unused)
     no-photo city-panel placeholder mark, so both stay in proportion. */
  --step-display:clamp(26px,3.2vw,40px);/* the vision headline, the no-photo city mark */
}

/* Avoid cream/white flash on overscroll -- scoped via :has() so bare `html`
   is never styled on pages that aren't the Solve Canada hub. */
html:has(body.solve-canada){
  background:#F3EDDF;
  -webkit-text-size-adjust:100%;
}

.solve-canada *,.solve-canada *::before,.solve-canada *::after{box-sizing:border-box;}
body.solve-canada{margin:0;padding:0;}
/* Body/UI default is --font-body (Libre Baskerville) as of 2026-07-12 --
   every element below inherits this unless it declares its own
   font-family. A short, named list of small-UI selectors override back to
   var(--font-sans) (Lexend) on purpose: uppercase + wide letter-spacing +
   very small size is a known bad combination for a serif with Baskerville's
   stroke contrast (verified by screenshot, not guessed) -- .eyebrow,
   .sc-eyebrow (hero), .city-mark small (no-photo placeholder), .city-chip,
   .leaf-tip (hero hover tooltip), .door h3 (card sub-heading label),
   .hub-diagram-spoke a, .inquiry-form .field label, .btn-submit, and
   .cities-band-links a. Everything else -- paragraphs, the FAQ, the
   founder/vision/city-panel copy, form inputs, and the contact card's
   copyright/fallback fine print -- reads fine in Baskerville at its size
   and stays on the new default. */
body.solve-canada{
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font-body);
  overflow-x:hidden;
  line-height:1.55;
  letter-spacing: 0.5px;
}
.solve-canada img{max-width:100%;display:block;}
.solve-canada a{color:inherit;}
.solve-canada .visually-hidden{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0;
}
.solve-canada :focus-visible{outline:2px solid var(--coral);outline-offset:3px;}

/* ======================================================================
   HERO -- ported from the approved map hero. Namespaced with sc- so it
   never collides with the rest of the page.
   ====================================================================== */
.solve-canada .sc-hero{
  position:relative;
  width:100%;height:100vh;min-height:560px;
  background:radial-gradient(ellipse at 50% 38%,#355a68 0%,var(--teal) 68%);
  overflow:hidden;
  display:flex;flex-direction:column;
  font-family:var(--font-sans);
}

/* The veil starts opaque and is lifted by map_hero_controller adding .is-revealed.
   The animation is a NO-JS FAILSAFE, not decoration: without it, any failure to
   load the JS module (importmap misresolution, a CSP change, one uncaught error)
   left the entire hero as a full-viewport opaque teal rectangle with no map --
   on the public homepage. The keyframe lifts the veil on its own clock, so a
   JS failure now costs the intro animation instead of the whole page.
   .is-revealed cancels it, so when JS IS working it stays in control. */
.solve-canada .sc-veil{
  position:absolute;inset:0;background:var(--teal);z-index:15;
  opacity:1;transition:opacity .6s ease;pointer-events:none;
  animation:sc-veil-failsafe .6s ease 5s forwards;
}
@keyframes sc-veil-failsafe{to{opacity:0;}}
.solve-canada .sc-hero.is-revealed .sc-veil{opacity:0;animation:none;}

.solve-canada .sc-wordmark{
  position:absolute;left:0;right:0;top:48%;
  transform:translateY(-50%);
  z-index:20;
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(16px,2.6vw,28px);
  text-align:center;
  padding:0 20px;
  transition:top 1.7s cubic-bezier(.16,.7,.15,1), transform 1.7s cubic-bezier(.16,.7,.15,1), gap 1.1s ease;
}
.solve-canada .sc-hero.is-settled .sc-wordmark{
  top:0;transform:translateY(0);
  align-items:flex-start;text-align:left;
  padding:clamp(18px,3vh,34px) clamp(20px,3.5vw,54px) 0;
  gap:8px;
}
.solve-canada .sc-eyebrow{
  margin:0;
  font-family:var(--font-sans);
  font-size:clamp(11px,1.5vw,14px);
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--cream);
  opacity:.85;
  transition:font-size 1.2s ease,opacity 1s ease;
}
.solve-canada .sc-hero.is-settled .sc-eyebrow{font-size:clamp(8.5px,1vw,11px);opacity:.72;letter-spacing:.08em;}

.solve-canada .sc-logotype{
  margin:0;
  font-family:var(--font-display);
  font-weight:400;
  font-size:clamp(48px,11vw,148px);
  letter-spacing:0;
  line-height:1;
  transition:font-size 1.7s cubic-bezier(.16,.7,.15,1);
}
.solve-canada .sc-hero.is-settled .sc-logotype{font-size:clamp(32px,4.8vw,64px);}
.solve-canada .sc-word{display:inline-block;}
.solve-canada .sc-solve{color:var(--cream);}
.solve-canada .sc-canada{color:var(--coral);margin-left:.22em;}

/* A slide is one or more lines that arrive together and leave together, so the
   box is reserved for two lines up front (min-height) and never reflows the
   wordmark above it when the second slide swaps a one-liner for a two-liner. */
.solve-canada .sc-intro-status{
  margin:clamp(22px,3.2vw,36px) 0 0;
  min-height:2.9em;
  display:flex;flex-direction:column;align-items:center;
  gap:.35em;
  font-family:var(--font-body);
  font-size:clamp(15px,1.6vw,19px);
  font-weight:400;
  letter-spacing:0;
  line-height:1.45;
  color:var(--cream);
  opacity:.88;
  transition:opacity .35s ease;
}
.solve-canada .sc-intro-line{display:block;}
.solve-canada .sc-intro-line + .sc-intro-line{opacity:.72;}
.solve-canada .sc-intro-status.is-fading{opacity:0;}
.solve-canada .sc-hero.is-settled .sc-intro-status{opacity:0;}

.solve-canada .sc-stagewrap{
  flex:1;min-height:0;
  display:flex;align-items:center;justify-content:center;
  padding:0;
  position:relative;z-index:5;
}
.solve-canada .sc-stage-shell{position:relative;--k:1;}
.solve-canada .sc-stage{
  position:relative;width:1600px;height:900px;
  transform-origin:0 0;
  transform:scale(var(--k,1));
}

/* Same no-JS failsafe as .sc-veil above: the provinces are invisible until the
   controller adds .is-assembling, so without the keyframe a JS failure left the
   map empty even once the veil lifted.

   The 5s delay is load-bearing and must stay LONGER than the controller's
   INTRO_HOLD_MS. At 2.4s it fired DURING the intro hold: the map assembled
   underneath a wordmark that was still full-size and centred, and the two
   collided on screen. The failsafe is a safety net for a JS failure, not part
   of the timeline — it must never beat the real animation to the punch. */
.solve-canada .sc-prov{
  position:absolute;
  opacity:0;
  transform:translate(var(--fx,0px),var(--fy,0px)) scale(.92);
  transition:opacity .64s cubic-bezier(.16,.8,.2,1),transform .7s cubic-bezier(.16,.8,.2,1);
  transition-delay:var(--delay,0ms);
  cursor:pointer;
  animation:sc-prov-failsafe .5s ease 5s forwards;
}
@keyframes sc-prov-failsafe{to{opacity:1;transform:translate(0,0) scale(1);}}
.solve-canada .sc-stage.is-assembling .sc-prov{opacity:1;transform:translate(0,0) scale(1);animation:none;}
.solve-canada .sc-stage.is-assembling .sc-prov.is-hot{transform:translate(0,-6px) scale(1);z-index:8;transition-delay:0s;}
.solve-canada .sc-prov:focus{outline:none;}
.solve-canada .sc-prov:focus-visible{outline:2px solid var(--cream);outline-offset:6px;border-radius:10px;}

.solve-canada .sc-art{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none;user-select:none;-webkit-user-drag:none;transition:opacity .32s ease,filter .32s ease;}
.solve-canada .sc-art.is-hover{opacity:0;}
.solve-canada .sc-prov.is-hot .sc-art.is-base{opacity:0;}
.solve-canada .sc-prov.is-hot .sc-art.is-hover{opacity:1;}
.solve-canada .sc-stage.has-hot .sc-prov:not(.is-hot) .sc-art.is-base{opacity:.35;filter:grayscale(.6) saturate(.55);}

.solve-canada .sc-leaves{position:absolute;inset:0;z-index:9;opacity:0;transition:opacity .9s ease .15s;pointer-events:none;}
.solve-canada .sc-stage.is-assembled .sc-leaves{opacity:1;pointer-events:auto;}

.solve-canada .leaf-marker{position:absolute;left:0;top:0;width:0;height:0;}
.solve-canada .leaf-marker-inner{
  position:absolute;left:0;top:0;
  transform:scale(calc(1 / var(--k,1)));
  transform-origin:0 0;
}
.solve-canada .leaf-pin{
  position:absolute;left:-11px;top:-11px;
  width:22px;height:22px;display:block;cursor:pointer;
  transform:translate(var(--px,0px), var(--py,0px));
  transition:transform .16s cubic-bezier(.2,.8,.2,1);
  z-index:2;
}
.solve-canada .leaf-pin img{
  width:100%;height:auto;display:block;
  filter:drop-shadow(0 0 1px rgba(31,55,64,.95))
         drop-shadow(0 0 2px rgba(31,55,64,.55))
         drop-shadow(0 3px 5px rgba(0,0,0,.4));
}
.solve-canada .leaf-pin:hover,.solve-canada .leaf-pin:focus-visible,.solve-canada .leaf-pin.is-linked{
  transform:translate(var(--px,0px), var(--py,0px)) translateY(-4px) scale(1.34);
  z-index:4;
}
.solve-canada .leaf-pin:focus{outline:none;}
.solve-canada .leaf-pin:focus-visible{outline:2px solid var(--cream);outline-offset:4px;border-radius:50%;}

.solve-canada .leaf-tip{
  position:absolute;left:50%;bottom:calc(100% + 10px);
  transform:translate(-50%,5px);
  padding:7px 14px;border-radius:999px;white-space:nowrap;
  background:var(--cream);color:var(--teal-deep);
  font-family:var(--font-sans);font-weight:700;font-size:13px;letter-spacing:.01em;
  box-shadow:0 7px 18px -5px rgba(0,0,0,.6);
  opacity:0;pointer-events:none;
  transition:opacity .16s ease,transform .16s ease;
}
.solve-canada .leaf-pin:hover .leaf-tip,.solve-canada .leaf-pin:focus-visible .leaf-tip,.solve-canada .leaf-pin.is-linked .leaf-tip{opacity:1;transform:translate(-50%,0);}

.solve-canada .sc-stage.has-pin .sc-prov .sc-art.is-base{opacity:.32;filter:grayscale(.6) saturate(.55);}

.solve-canada .sc-cityrow{
  position:absolute;left:0;right:0;bottom:0;z-index:10;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:10px;
  padding:0 20px clamp(16px,3vh,30px);
  pointer-events:none;
}
.solve-canada .sc-cityrow .city-chip{pointer-events:auto;}
.solve-canada .city-chip{
  display:inline-flex;align-items:center;text-decoration:none;
  font-family:var(--font-sans);font-weight:500;font-size:13px;
  letter-spacing:.02em;
  color:var(--cream);
  background:rgba(243,237,223,.04);
  border:1px solid rgba(243,237,223,.28);
  padding:10px 20px;border-radius:999px;
  transition:transform .16s ease,box-shadow .16s ease,background .16s ease;
}
.solve-canada .city-chip span{color:var(--coral);}
.solve-canada .city-chip:hover,.solve-canada .city-chip:focus-visible,.solve-canada .city-chip.is-linked{
  transform:translateY(-3px);
  background:rgba(243,237,223,.1);
  box-shadow:0 9px 22px -6px rgba(0,0,0,.55);
}
.solve-canada .city-chip:focus-visible{outline:2px solid var(--coral);outline-offset:2px;}

@media (max-width:640px){
  .solve-canada .city-chip{font-size:12px;padding:8px 14px;}
  .solve-canada .sc-cityrow{gap:7px;}
  .solve-canada .leaf-tip{font-size:12px;padding:6px 12px;}
  .solve-canada .leaf-pin{width:17px;height:17px;left:-8.5px;top:-8.5px;}
  .solve-canada .sc-eyebrow{letter-spacing:.08em;}
  .solve-canada .sc-hero.is-settled .sc-eyebrow{letter-spacing:.16em;font-size:8px;}
}

@media (prefers-reduced-motion:reduce){
  .solve-canada .sc-veil,.solve-canada .sc-wordmark,.solve-canada .sc-eyebrow,.solve-canada .sc-logotype,.solve-canada .sc-prov,.solve-canada .sc-art,.solve-canada .sc-leaves{transition-duration:.001ms !important;transition-delay:0s !important;}
  /* The failsafe keyframes above are animations, not transitions, so the rule
     on the line above does not touch them. Without this they would still crawl
     through a 2.4s delay for a user who asked for no motion. Collapse them to
     instant rather than removing them: they are the no-JS safety net. */
  .solve-canada .sc-veil,.solve-canada .sc-prov{animation-duration:.001ms !important;animation-delay:0s !important;}
}

/* City panels (shared grid + photo treatment) */
.solve-canada .cities{padding:0;}
.solve-canada .city-panel{
  display:grid;grid-template-columns:1fr;
  min-height:clamp(420px,72vh,760px);
}
@media (min-width:860px){
  .solve-canada .city-panel{grid-template-columns:1fr 1fr;}
  .solve-canada .city-panel.is-flip .city-media{order:2;}
  .solve-canada .city-panel.is-flip .city-copy{order:1;}
}
.solve-canada .city-media{
  position:relative;min-height:280px;
  background:var(--teal);
  overflow:hidden;
}
.solve-canada .city-media img{width:100%;height:100%;object-fit:cover;display:block;position:absolute;inset:0;}
.solve-canada .city-media.no-photo{
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(155deg,var(--teal) 0%,var(--teal-deep) 62%,var(--coral) 190%);
}
.solve-canada .city-media.no-photo .city-mark{
  font-family:var(--font-display);color:var(--cream);
  font-size:var(--step-display);letter-spacing:.02em;
  opacity:.9;text-align:center;padding:0 24px;
}
.solve-canada .city-media.no-photo .city-mark small{
  display:block;font-family:var(--font-sans);font-size:var(--step-eyebrow);letter-spacing:.2em;
  text-transform:uppercase;color:var(--coral);margin-bottom:16px;font-weight:600;
}
.solve-canada .photo-credit{
  position:absolute;right:14px;bottom:12px;z-index:2;
  font-size:var(--step-fine);color:var(--cream);opacity:.8;
  background:rgba(28,51,60,.45);padding:4px 9px;border-radius:999px;
  text-decoration:none;
}
.solve-canada .photo-credit:hover{opacity:1;}
.solve-canada .city-copy{
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(40px,6vw,80px);
  background:var(--cream);
}
