#!/usr/bin/env python3
# ---------------------------------------------------------------------------
# inner-service.html — the inner service page (Car Accident Claims) in
# home_v1's design language, opening on the PICKED HERO.
#
# v1 opened on `.sopen`: type only, no photograph, because Darren's ban on the
# homepage intro image had never been ruled on for inner pages. That question
# went to Adi as an option sheet (hero-inner.html), and on 2026-08-30 he picked
# **A1** — colour block, photograph, contact panel — and then re-cut it twice.
# This build replaces `.sopen` with that hero and changes nothing else.
#
# NOTHING HERE IS RETYPED. Three lifts happen at build time:
#   * home_v1.html      -> stylesheet, header, contact band, articles/FAQ,
#                          footer, modal, scripts        (as in v1)
#   * gen_heroinner_r2.py -> the hero's own CSS and its markup
#   * gen_heroinner.py    -> the hexagon, breadcrumb and title rules the hero
#                            shares with the option sheet
# so the hero on this page and the hero on the option sheet cannot drift, and
# neither can this page and the homepage.
#
# `.a1` could not be reused as the hero's scope on this page: home_v1's footer
# already owns it (`.nfoot .fc .a1`, a decorative hexagon). Everything is
# re-scoped to `.shero`, and the build asserts nothing bare escaped.
# ---------------------------------------------------------------------------
import io, re, sys

SRC  = "/srv/apps/leaguelaw/wp-content/prototype/home_v1.html"
OUT   = "/srv/apps/leaguelaw/wp-content/prototype/inner-service.html"
R1GEN = "/srv/apps/leaguelaw/prototyping/gen_heroinner.py"
R2GEN = "/srv/apps/leaguelaw/prototyping/gen_heroinner_r2.py"
SCOPE = ".shero"

src = io.open(SRC, encoding="utf-8").read()


def between(a, b, label):
    """Slice src between two markers, both kept."""
    i = src.find(a)
    assert i >= 0, "start marker missing: " + label
    j = src.find(b, i + len(a))
    assert j >= 0, "end marker missing: " + label
    return src[i:j]


STYLE  = between("<style>", "</style>", "style").replace("<style>", "", 1)
HEADER = between("<!-- 1 · header", "<!-- 2 · triage", "header")
CBAND  = between("<!-- 3 · contact band", "<!-- 4 · the bench", "cband")
KNW    = between("<!-- 6 · articles + FAQ", "<!-- 7 · footer", "knw")
FOOTER = between("<!-- 7 · footer", "<!-- consultation tab", "footer")
MODAL  = between("<!-- consultation tab", "<script>", "modal + fold ruler")
SCRIPT = between("<script>\n// \"Inside the league\"", "</script>", "scripts")

# ---------------------------------------------------------------------------
# the thirteen injury claim types — same list, brows and slugs home_v1's
# Injuries panel already uses, so the two pages agree
# ---------------------------------------------------------------------------
CLAIMS = [
    ("Road Accidents", "Car Accident Claims",        "/our-services/bc-injury-claims/car-accident-claims/",        "car-accidents"),
    ("Road Accidents", "Motorcycle Accident Claims", "/our-services/bc-injury-claims/motorcycle-accident-claims/", "motorcycle-accidents"),
    ("Road Accidents", "Cyclist Accident Claims",    "/our-services/bc-injury-claims/cyclist-accident-claims/",    "cyclist-accidents"),
    ("Road Accidents", "Passenger Injury Claims",    "/our-services/bc-injury-claims/passenger-injury-claims/",    "passenger-injury"),
    ("Road Accidents", "Pedestrian Injury Claims",   "/our-services/bc-injury-claims/pedestrian-injury-claims/",   "pedestrian-injury"),
    ("Road Accidents", "Hit and Run Injury Claims",  "/our-services/bc-injury-claims/hit-and-run-injury-claims/",  None),
    ("On Premises",    "Slip and Fall",              "/our-services/bc-injury-claims/slip-and-fall/",              "slip-and-fall"),
    ("On Premises",    "Premises Liability Claims",  "/our-services/bc-injury-claims/premises-liability-claims/",  "premises-liability"),
    ("On Premises",    "School Accident Claims",     "/our-services/bc-injury-claims/school-accident-claims/",     None),
    ("On Premises",    "Product Liability Claims",   "/our-services/bc-injury-claims/product-liability/",          None),
    ("Other Claims",   "Dog Attack",                 "/our-services/bc-injury-claims/dog-attack/",                 "dog-attack"),
    ("Other Claims",   "Boating Accidents",          "/our-services/bc-injury-claims/boat-accident-injuries/",     "boating-injury"),
    ("Other Claims",   "Assault &amp; Battery",      "/our-services/bc-injury-claims/assault-battery/",            None),
]
CURRENT = "Car Accident Claims"

# the five lawyers home_v1's Injuries panel already names, in its order
INJURY_BENCH = [
    ("Darren Williams",  "/lawyers/darren-williams/",  "/wp-content/uploads/DARRENorangebowtie.jpg",
     "Injury, estates &amp; marine litigation"),
    ("Joji Kawaguchi",   "/lawyers/joji-kawaguchi/",   "/wp-content/uploads/Joji-20220126-028-Hi-Res-scaled-e1709583455555-761x1024.jpg",
     "Civil litigation, injury &amp; estates"),
    ("Matthew Melnyk",   "/lawyers/matthew-melnyk/",   "/wp-content/uploads/matthew-melnyk-sm.jpg",
     "Injury, estates, insurance &amp; marine"),
    ("Reid Warren",      "/lawyers/reid-warren/",      "/wp-content/uploads/Reid-20240403-030-Hi-Res-scaled-e1715983076700-761x1024.jpg",
     "Personal injury &amp; estate litigation"),
    ("Georgia Lockhart", "/lawyers/georgia-lockhart/", "/wp-content/uploads/Georgia-20260119-069-Hi-Res-V2-BW-scaled-e1773087958989-761x1024.jpg",
     "Civil litigation, estates &amp; marine"),
]

# the live page's Part 7 list, split at its own comma/preposition so the
# figure can carry the weight. Not one word is added or removed.
BENEFITS = [
    ("Up to $150,000",     "in medical and rehabilitation expenses"),
    ("Up to $300 per week", "in wage loss benefits for those who were totally disabled from work "
                            "within 20 days of the accident. Note these benefits are payable for a "
                            "maximum of 104 weeks."),
    ("Homemaker benefits",  "(limits apply)."),
    ("Death benefits",      "&ndash; limited amounts paid to surviving spouses and children."),
]

# ---------------------------------------------------------------------------
EXTRA_CSS = r"""
  /* =====================================================================
     INNER SERVICE PAGE — additions only. Everything above is home_v1's
     stylesheet, lifted verbatim at build time.
     The page answers the same job the old inner page did (title, breadcrumb,
     copy, sibling nav, two contact forms) in home_v1's vocabulary: no hero
     photograph, contact loud and early, outlined cards, the logo-underline
     hover, the swarm button.
     ===================================================================== */

  /* current practice area in the main nav */
  .nheader .services .mi.cur > a { color: var(--orange); box-shadow: inset 0 -2px 0 var(--orange); }

  /* ---------- 2 · hero — A1, picked 2026-08-30.
     v1 opened on type alone (`.sopen`) because Darren's ban on the homepage
     intro image had never been ruled on for inner pages. Adi picked A1 off the
     option sheet, so the page opens on a photograph after all — and the whole
     of that hero's CSS is injected here, lifted from the sheet's generators
     and re-scoped `.a1` -> `.shero`. Nothing about it is written twice.
     ---------- */
__HERO_CSS__

  /* ---------- 3 · body — 768 / 512 on the same five-cell lattice the
     contact band and the articles/FAQ block already use. ---------- */
  .sbody { background: #fff; padding: 54px 0 66px; }
  /* The page's own h2 and lede used to live in the opener. They cannot follow
     the title into the hero: the title panel is brand orange, and white on
     brand orange is 3.03:1 — legal for the 38px title, illegal for anything at
     reading size. So they open the body instead, on white, where they are at
     full contrast and still the first words after the hero. */
  .sbody .slead { padding-bottom: 24px; margin-bottom: 26px; border-bottom: 1px solid var(--line); }
  .sbody .slead h2 { font-family: Raleway, sans-serif; font-weight: 400; font-size: 22px;
                     line-height: 1.5; color: var(--brown); margin-bottom: 14px; max-width: 40ch; }
  .sbody .slead .lede { font-size: 17.5px; line-height: 1.8; color: #4A453F; max-width: 62ch; }
  .sbody .cols { display: flex; align-items: flex-start; }
  .sbody .col { width: 768px; flex: none; padding-right: 64px; }
  .sbody .rail { flex: 1; align-self: stretch; padding-left: 60px; border-left: 1px solid var(--line); }
  .sbody .rin { position: sticky; top: 116px; }
  .prose { font-size: 16.5px; line-height: 1.9; color: #4A453F; }
  .prose p { margin-bottom: 22px; }
  .prose p:last-child { margin-bottom: 0; }
  .prose a { color: var(--orange); box-shadow: inset 0 -1px 0 rgba(239,109,62,.45); }
  .prose a:hover { box-shadow: inset 0 -2px 0 var(--orange); }
  /* the old page floated a photograph right into the text; kept, at the
     house's 16:9 crop instead of the 4:3 monochrome one */
  .prose figure.side { float: right; width: 300px; margin: 4px 0 22px 34px; position: relative; }
  .prose figure.side img { width: 100%; height: 169px; object-fit: cover; display: block; }
  .prose figure.side figcaption { font-size: 12px; line-height: 1.6; color: #9A948B; margin-top: 10px; }
  .prose figure.side .ph-tag { position: absolute; left: 10px; top: 139px; background: rgba(66,60,55,.72);
                               color: #fff; font-size: 10px; letter-spacing: .06em;
                               text-transform: uppercase; padding: 4px 8px; }

  /* the four Part 7 benefits, lifted out of the bullet list into the
     outlined-cell vocabulary the locations and sub-service cards use */
  .pgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-items: start;
           margin: 6px 0 26px; clear: both; }
  .pcard { border: 1px solid var(--line); background: #fff; padding: 20px 22px 22px;
           min-height: 104px; transition: border-color .18s ease; }
  .pcard:hover { border-color: var(--orange); }
  .pcard .amt { display: block; font-family: Raleway, sans-serif; font-weight: 800; font-size: 21px;
                letter-spacing: .02em; color: var(--orange); margin-bottom: 7px; }
  .pcard .qual { font-size: 13.5px; line-height: 1.7; color: var(--body-text); }

  /* rail: the consultation card, then the sibling claims — the old page's
     sidebar, doing the same two jobs */
  .rcard { background: var(--paper); border: 1px solid var(--line); border-top: 4px solid var(--orange);
           padding: 26px 28px 28px; margin-bottom: 34px; }
  .rcard .rh { font-family: Raleway, sans-serif; font-weight: 800; font-size: 19px; color: var(--brown);
               letter-spacing: .02em; margin-bottom: 8px; }
  .rcard p { font-size: 13.5px; line-height: 1.75; color: var(--body-text); margin-bottom: 18px; }
  .rcard .rphone { display: block; font-family: Raleway, sans-serif; font-weight: 800; font-size: 26px;
                   color: var(--orange); margin-bottom: 4px; }
  .rcard .rphone .cn { display: block; color: var(--teal); font-weight: 600; font-size: 10.5px;
                       letter-spacing: .16em; }
  .rcard .rsafe { display: block; font-size: 11.5px; color: #9A948B; margin-top: 12px; }
  .rnav .fh { font-family: Raleway, sans-serif; font-weight: 700; font-size: 11.5px; letter-spacing: .14em;
              text-transform: uppercase; color: #8D867E; margin-bottom: 14px; }
  .rnav .rlist { column-count: 2; column-gap: 22px; }
  .rnav .rlist a { display: block; position: relative; break-inside: avoid; font-size: 13px; font-weight: 600; color: #4A453F;
                   padding: 9px 2px 9px 17px; border-bottom: 1px solid #EEECE7; transition: color .14s ease; }
  .rnav .rlist a::before { content: ""; position: absolute; left: 0; top: 50%; width: 9px; height: 10px;
                           background: var(--orange); clip-path: polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%);
                           transform: translateY(-50%) translateX(-7px) scale(0); transition: transform .14s ease; }
  .rnav .rlist a:hover { color: var(--orange); }
  .rnav .rlist a:hover::before { transform: translateY(-50%) translateX(0) scale(1); }
  .rnav .rlist a.cur { color: var(--orange); }
  .rnav .rlist a.cur::before { transform: translateY(-50%) translateX(0) scale(1); }

  /* ---------- 5 · sibling claims — the area panel's own card grid, opened
     out flat because on this page there is nothing to open ---------- */
  .sibs { background: var(--paper); padding: 60px 0 8px; }
  .sibs .sgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
  .sibs .abox { min-height: 68px; }
  .sibs .abox.cur { background: #FBF6F1; box-shadow: inset 0 -4px 0 var(--orange); }
  .sibs .abox.cur .bn { color: var(--orange); }
  .sibs .abox.cur .ebrow::after { content: " · you are here"; color: var(--orange); }

  /* injury bench: five, not twelve — same cells, one fewer column */
  .bench.five { grid-template-columns: repeat(5, 1fr); }
  .teams .benchnote { text-align: center; margin-top: 26px; font-size: 11.5px; color: #9A948B; }
"""



# ---------------------------------------------------------------------------
# THE HERO, LIFTED FROM THE OPTION SHEET
#
# The picked hero is A1 from hero-inner.html. Rather than copy its CSS here —
# where it would quietly diverge the first time either file is touched — both
# halves are read out of the option sheet's own generators at build time and
# re-scoped from `.a1` to `.shero`.
# ---------------------------------------------------------------------------
def _scope(css, sel, strip=None):
    """Re-scope a flat, hand-written CSS block: drop `strip` off the front of
    every selector, then put `sel` on the front instead.

    The block must be flat: no @-rules, no nesting. Comments are lifted out
    first so their prose can never be parsed as a selector, then put back.
    Both facts are asserted, and so is the brace count, because a rescoper
    that silently drops a rule produces a page that merely looks wrong.
    """
    holes = []

    def stash(m):
        holes.append(m.group(0))
        return "\x00%d\x00" % (len(holes) - 1)

    body = re.sub(r"/\*.*?\*/", stash, css, flags=re.S)
    assert "@" not in body, "block contains an @-rule; _scope cannot handle it"
    braces = body.count("{")
    assert braces == body.count("}"), "unbalanced braces before scoping"

    out = []
    for chunk in body.split("}"):
        if "{" not in chunk:
            out.append(chunk)
            continue
        selpart, decls = chunk.split("{", 1)
        # whatever sits in front of the selector — indentation and any comment
        # that was stashed above — belongs OUTSIDE the prefix, or the scope
        # lands in front of the comment and the rule escapes unscoped
        lead = re.match(r"(?:\s|\x00\d+\x00)*", selpart).group(0)
        sels = [x.strip() for x in selpart[len(lead):].split(",")]
        if strip:
            # `.a1 .tp` becomes `.shero .tp`, not `.shero .a1 .tp` — the sheet's
            # scope is REPLACED, not nested inside the page's
            sels = [x[len(strip):].lstrip() if x.startswith(strip + " ") else x
                    for x in sels]
        sels = [sel + " " + x for x in sels]
        out.append(lead + ", ".join(sels) + " {" + decls)
    body = "}".join(out)

    assert body.count("{") == braces, "a rule was lost while scoping"
    body = re.sub(r"\x00(\d+)\x00", lambda m: holes[int(m.group(1))], body)
    return body


def _hero_css():
    r2 = io.open(R2GEN, encoding="utf-8").read()
    r1 = io.open(R1GEN, encoding="utf-8").read()

    # (a) the pieces the hero shares with every option on the sheet: the
    #     hexagon (declared as a ratio), the breadcrumb, the title, the
    #     placeholder tag on the photograph.
    i = r1.index("THE HEXAGON, FIXED.")
    j = r1.rindex("/*", 0, i)
    j = r1.rindex("\n", 0, j) + 1
    k = r1.index("  /* ---------- A1", j)
    shared = r1[j:k]
    a = shared.find("  /* contact block")           # round 1's bespoke block,
    b = shared.find("  .phtag {")                   # replaced by home_v1's .call
    assert 0 < a < b, "could not find round 1's .cc block to drop"
    shared = shared[:a] + shared[b:]

    # (b) A1's own rules, as re-cut on 2026-08-30.
    i = r2.index('A1CSS = r"""')
    a1 = r2[i + len('A1CSS = r"""'):r2.index('"""', i + 12)]

    css = shared + a1
    for gone in ("--muted", "--deep", "--band-dark"):
        assert gone not in css, "hero CSS wants %s, which home_v1 does not define" % gone
    assert "aspect-ratio:.8660254" in css, "the hexagon ratio did not survive the lift"
    assert "height:10.392px" in css, "the swarm hexagon ratio did not survive the lift"
    assert "min-height:380px" in css, "the band lost its min-height"
    assert "padding:40px 0 40px 60px" in css, "the contact panel lost its left gap"

    css = _scope(css, SCOPE, strip=".a1")

    # Nothing may have escaped the scope — a bare .hex or .crumbs here would
    # collide with home_v1's own vocabulary further down the page. The check
    # runs on the RULES ONLY: the comments talk about `.call` and `.tp` in
    # prose, and prose is not a selector.
    rules = re.sub(r"/\*.*?\*/", "", css, flags=re.S)
    for bare in (".hex", ".crumbs", ".htitle", ".hsub", ".hrule", ".phtag",
                 ".cbar", ".swarmbtn", ".band", ".tp", ".ph", ".cp", ".call",
                 ".in", ".lead", ".avail", ".big", ".officenote", ".frow2"):
        assert not re.search(r"(^|\})\s*" + re.escape(bare) + r"[ .:{,]", rules, re.M), \
            "%s escaped the %s scope" % (bare, SCOPE)
    assert ".a1" not in rules, "an .a1 selector survived the re-scope"
    assert rules.count(SCOPE) >= 30, "suspiciously few scoped rules: %d" % rules.count(SCOPE)
    return css


def _hero_markup():
    """A1's markup, taken from the option sheet's own builder.

    The sheet's A1() also emits the sheet's header stand-in and wraps itself in
    `.a1`; here the page's real header is home_v1's, and the scope is `.shero`.
    Both are cut, and the cut is asserted rather than assumed.
    """
    r2 = io.open(R2GEN, encoding="utf-8").read()
    ns = {}
    exec(compile(r2[r2.index("PHOTO = "):r2.index("HEAD = \"\"\"")], R2GEN, "exec"), ns)
    html = ns["A1"]()
    i = html.index("</header>") + len("</header>")
    html = '<section class="shero">' + html[i:]
    assert html.count("<h1") == 1 and "passengerclaim" in html and 'class="call"' in html
    assert "<header" not in html, "the sheet's header stand-in survived the cut"
    return html


# ---------------------------------------------------------------------------
def crumbs():
    return """      <nav class="crumbs" aria-label="Breadcrumb">
        <a href="/">Home</a><i class="hexpt"></i>
        <a href="/our-services/">What We Do</a><i class="hexpt"></i>
        <a href="/our-services/bc-injury-claims/">Injury Claims</a><i class="hexpt"></i>
        <span class="here">Car Accident Claims</span>
      </nav>
"""


def opener():
    """The picked hero, in place of v1's type-only opener.

    v1 put the breadcrumb inside `.sopen`; A1 carries its own on the white
    strip above the band, so `crumbs()` is no longer called from here — it is
    kept below because the hero's breadcrumb is the sheet's, and if the hero is
    ever swapped again the page still has one of its own to fall back to.
    """
    return ("""
<!-- 2 · hero — A1 off the option sheet (hero-inner.html), picked 2026-08-30:
     colour block with the title, the photograph, and home_v1's own contact
     block on brown. Breadcrumb on a white strip above the band. -->
""" + _hero_markup() + "\n")


def benefits_cards():
    return "\n".join(
        '          <div class="pcard"><span class="amt">%s</span><span class="qual">%s</span></div>'
        % (a, b) for a, b in BENEFITS)


def body():
    return """
<!-- 3 · body — the live page's copy, in order, verbatim. The only change is
     that the Part 7 bullet list is set as four outlined cards; the words are
     the list's own. -->
<section class="sbody">
  <div class="wrap">
    <div class="cols">
      <div class="col">

        <!-- the deck and lede the old opener carried; see .slead in the CSS
             for why they are here and not in the hero -->
        <div class="slead">
          <h2>League &amp; Williams are Experienced Car Accident Injury Claims Lawyers</h2>
          <p class="lede">Our team of lawyers are experienced in car accident injury claims &amp; work
          to ensure that injured victims recover their fullest potential. Free consultations.</p>
        </div>

        <div class="prose">

          <figure class="side">
            <img src="/wp-content/prototype/img/injuries-thumb-clean.jpg" alt="">
            <span class="ph-tag">Placeholder &middot; November shoot</span>
            <figcaption>An experienced injury lawyer can help you recover after a car accident by
            handling your ICBC claim, ensuring access to treatments needed to recover, and
            advocating for fair compensation.</figcaption>
          </figure>

          <p>Being involved in a car accident can be scary and often those injured in motor vehicle
          accidents are unaware of how to ensure the best recovery possible.&nbsp; Those injured in
          car accidents in British Columbia, whether as a driver, passenger, pedestrian or cyclist
          are entitled to pursue compensation for their injuries.&nbsp; Car accident victims who are
          injured may claim for pain and suffering, out-of-pocket expenses, loss of housekeeping
          capacity, loss of income and diminished earning capacity, and for cost of future care.&nbsp;
          The kind of compensation available and the amounts will depend on the extent of the
          injuries, the impact they have had on the victim&rsquo;s life, and whether or not the victim
          was partly at fault for their injuries.</p>

          <p>Typically those involved in car&nbsp;accidents in British Columbia may make two types of
          claims &ndash; a Tort claim and a Part 7 claim.</p>

          <p>A Tort claim is available for those who are injured and who can prove that another person
          was, at least partly, at fault or responsible for causing the accident.&nbsp; The person must
          also establish that they suffered damages, and that those damages were the result of the
          accident.&nbsp; It is important to note that in order to make a tort claim, that claim must
          also be filed within 2 years of the date of the accident (this is the limitation date).&nbsp;
          If a person cannot prove that their injuries were caused by the accident, then the injured
          person is limited in their tort claim to the damages that they can prove were the result of
          the accident. &nbsp;If a person cannot prove that another person is at least partly at fault,
          then their claims for their injuries will be limited to a Part 7 claim, also known as a
          no-fault benefits claim.</p>

          <p>A Part 7 claim refers to the &ldquo;no-fault&rdquo; benefits that are payable to accident
          victims in BC, even if they are wholly at fault for their injuries.&nbsp; To receive these
          benefits, the person must have an insurance policy with ICBC; or, live in a household with
          someone who has an insurance policy with ICBC; or, was the occupant of a vehicle licensed in
          BC; or was a cyclist or pedestrian who has collided with a vehicle insured in BC.&nbsp; It is
          important to note that notice and limitation periods apply to Part 7 claims.&nbsp; Although
          the claimant does not need to prove that someone else was at fault for the accident, they
          must still prove that the injuries that they sustained were the result of the accident.</p>

          <p>Under Part 7, a person is entitled to the following benefits:</p>

          <div class="pgrid">
%s
          </div>

          <p>If you, or someone you know was injured in a car accident, speaking with an experienced
          injury lawyer and making informed decisions about their claim is critical.&nbsp; The lawyers
          at League and Williams provide free consultations to those injured in car accidents and have
          the experience needed to help injured victims recover to their fullest potential. &nbsp;We
          <a href="/contact-our-lawyers/">may be contacted</a> by phone 250-888-0002 or via email
          at&nbsp;<a href="mailto:info@leaguelaw.com">info@leaguelaw.com.</a></p>

        </div>
      </div>

      <aside class="rail">
       <div class="rin">
        <div class="rcard">
          <div class="rh">WE&rsquo;VE GOT YOUR BACK</div>
          <p>Free consultations for those injured in car accidents. Our email is monitored seven days
          a week and we will get back to you shortly.</p>
          <a class="rphone" href="tel:+12508880002"><span class="cn">Call now</span>250-888-0002</a>
          <span class="rsafe">&#128274; Your information is kept safe.</span>
          <div style="margin-top:18px">
            <button class="swarmbtn" type="button" data-open-consult data-consult-slug="car-accidents">Book Consultation<i class="w1"></i><i class="w2"></i><i class="w3"></i></button>
          </div>
        </div>
        <div class="rnav">
          <div class="fh">Injury claims</div>
          <div class="rlist">
%s
          </div>
        </div>
       </div>
      </aside>

    </div>
  </div>
</section>
""" % (benefits_cards(), rail_list())


def rail_list():
    out = []
    for brow, name, href, slug in CLAIMS:
        cur = ' class="cur"' if name == CURRENT else ''
        out.append('            <a href="%s"%s>%s</a>' % (href, cur, name))
    return "\n".join(out)


def siblings():
    cards = []
    for brow, name, href, slug in CLAIMS:
        if name == CURRENT:      # you are already here
            continue
        cur = False
        acts = ('<a class="bact" href="%s" title="View service"><i class="fa fa-arrow-right"></i></a>'
                % href)
        if slug:
            acts += ('<button class="bact" type="button" data-open-consult data-consult-slug="%s" '
                     'title="We&rsquo;ve got your back — book a consultation">'
                     '<i class="fa fa-envelope"></i></button>' % slug)
        else:
            acts += ('<button class="bact" type="button" data-open-consult '
                     'title="We&rsquo;ve got your back — book a consultation">'
                     '<i class="fa fa-envelope"></i></button>')
        cards.append(
            '        <div class="abox has-acts%s"><span class="ebrow">%s</span>'
            '<span class="bn">%s</span><span class="bacts">%s</span></div>'
            % (' cur' if cur else '', brow, name, acts))
    return """
<!-- 5 · the other injury claims — the area panel's card grid, laid out flat.
     Same boxes, same two actions (open the service · book a consultation). -->
<section class="sibs" aria-label="Other injury claims">
  <div class="wrap">
    <div class="shead">
      <span class="kick"><i class="hexpt"></i>Injuries</span>
      <h2>Other <b>injury claims</b></h2>
    </div>
    <div class="sgrid">
%s
    </div>
  </div>
</section>
""" % "\n".join(cards)


def bench():
    rows = "\n".join(
        '      <a class="bx" href="%s">\n'
        '        <span class="bph"><img src="%s" alt=""></span>\n'
        '        <span class="bnm">%s</span>\n'
        '        <span class="bfo">%s</span>\n'
        '      </a>' % (href, img, name, focus)
        for name, href, img, focus in INJURY_BENCH)
    return """
<!-- 6 · the injury bench — the five lawyers home_v1's Injuries panel already
     names, shown as the bench cells rather than a crossfade. Who actually
     staffs a matter is still the firm's call (flagged, not invented). -->
<section class="teams">
  <div class="wrap">
    <div class="head">
      <span class="kick"><i class="hexpt"></i>Behind every team</span>
      <h2>Your <b>injury team.</b></h2>
      <div class="cred">
        <span class="stars">&#9733;&#9733;&#9733;&#9733;&#9733;</span> <span><b>4.9</b> on Google</span>
        <span class="dot">&middot;</span> <span>Free consultations for injury claims</span>
      </div>
    </div>
    <div class="bench five">
%s
    </div>
    <div class="benchnote">Lawyers whose stated practice includes injury claims &mdash; confirm the
    matter team with the firm.</div>
  </div>
</section>
""" % rows


# ---------------------------------------------------------------------------
def build():
    head = """<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title>League Law &mdash; Car Accident Claims</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700;800&family=Open+Sans:ital,wght@0,400;0,600;0,700;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>__STYLE__
__EXTRA__
</style>
</head>
<body>
<span id="top"></span>
"""
    extra = EXTRA_CSS.replace("__HERO_CSS__", _hero_css())
    assert "__HERO_CSS__" not in extra, "the hero CSS was never injected"
    head = head.replace("__STYLE__", STYLE).replace("__EXTRA__", extra)

    # mark Injuries as the current practice area in the lifted header
    header = HEADER.replace('<div class="mi"><a href="#">Injuries</a>',
                            '<div class="mi cur"><a href="/our-services/bc-injury-claims/">Injuries</a>', 1)
    assert 'class="mi cur"' in header, "could not mark the current nav item"

    parts = [head, header, opener(), body(), CBAND, siblings(), bench(), KNW,
             FOOTER, MODAL, "<script>\n// \"Inside the league\"", SCRIPT,
             "</script>\n</body>\n</html>\n"]
    return "".join(parts)


if __name__ == "__main__":
    html = build()
    dest = sys.argv[1] if len(sys.argv) > 1 else OUT
    io.open(dest, "w", encoding="utf-8").write(html)
    print("wrote %s (%d bytes)" % (dest, len(html)))
