/* ==========================================================================
   Design system v2, district-hub family sheet.

   Loaded only on the 22 district hub routes, after tokens.css and school.css,
   because districts.11tydata.js declares designSheet: "hub". Nothing here is
   shared, so nothing here may define a class that another family would need:
   if a rule belongs to every page it goes in school.css, centrally, and this
   sheet does not duplicate it.

   The hub markup therefore uses only the sm- classes school.css already
   defines. What follows adjusts them for a routing page: a card that is itself
   a link, place lists that run from 2 items to 22, and prices set at the pack's
   display size. No class is invented here, so every class on a hub page has a
   rule in school.css as well, which is what check-unstyled-classes.mjs reads.

   Tokens only. Values live in tokens.css and the spacing scale is named by
   VALUE and skips numbers: --space-13 does not exist, and an undefined var()
   drops the whole declaration silently.
   ========================================================================== */

/* ---------- 1. The routing grids ---------- */

/* These are the two place lists: the areas inside the district, and its test
   centres. Their item counts are 2, 3, 4, 5, 6, 7, 8, 9, 10 and 22 for the
   areas, and 1 or 2 for the test centres.
   auto-fit picks its column count from the available width, not from the item
   count, which is how six cards ended up in four columns with half of the
   second row empty. So the count is picked from the item count here, choosing
   the arrangement whose last row is short by one cell at most.
   The selector carries both classes so it out-specifies school.css's own
   six-card rule, and every rule here is inside a min-width query so the
   single-column phone layout is never overridden. */
@media (min-width: 1200px) {
  /* 4 + 3 and 4 + 4. */
  .sm-cards.sm-junctions:has(> :nth-child(4):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(7):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(8):last-child) {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* 3, 3 + 2, 3 + 3 and 3 + 3 + 3. */
  .sm-cards.sm-junctions:has(> :nth-child(3):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(5):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(6):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(9):last-child) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* Ten goes 5 + 5. Four would strand a row of two, and three would strand a
     row of one. */
  .sm-cards.sm-junctions:has(> :nth-child(10):last-child) {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  /* Two cells side by side, and the one list of 22 (Dun Laoghaire-Rathdown),
     where two columns is the only arrangement under eleven that fills its last
     row. A long district reads as a directory, which is what a hub is. */
  .sm-cards.sm-junctions:has(> :nth-child(2):last-child),
  .sm-cards.sm-junctions:has(> :nth-child(22):last-child) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Between the tablet break and 1200px there is no room for four columns: a
   212px cell cannot hold "Test centre: Dun Laoghaire (3.5km)" on one line. Two
   columns leaves a last row short by one at most for every count there is.
   The :has() keeps this at the same specificity as the rules it overrides,
   because a plain class collapse loses to a two-part selector at every width. */
@media (min-width: 769px) and (max-width: 1199px) {
  .sm-cards.sm-junctions:has(> :nth-child(3)) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- 2. A card that is itself a link ---------- */

/* Every area and test centre card is a single anchor, as the v1 page had it, so
   the whole cell is the target rather than a small link inside it. */
.sm-cards a.sm-card {
  text-decoration: none;
  transition: background var(--dur-fast), border-color var(--dur-fast), transform var(--dur-base);
}
.sm-cards a.sm-card:hover {
  background: var(--color-panel-raised);
  transform: var(--lift-sm);
}

/* The link label sits on the floor of the card, so the labels line up across a
   row whose cards hold different amounts. The arrow is drawn here and never
   written as a text node: a glyph inside the label changes the label, and the
   v1 page's own arrows are decoration the parity gate strips from both sides. */
.sm-cards a.sm-card > span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  margin-top: auto;
  padding-top: var(--space-6);
  font-family: var(--font-display);
  font-size: var(--fs-caption);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--color-accent);
}
.sm-cards a.sm-card > span:not(.sm-pill)::after { content: "→"; }

/* An area whose page does not exist yet keeps the v1 page's own wording, and
   takes the pill the system already uses for a place with no page of its own:
   muted, no arrow, and not pretending to be a link label. */
.sm-cards a.sm-card > span.sm-pill {
  align-self: flex-start;
  padding: var(--space-4) var(--space-7);
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: var(--fw-bold);
  letter-spacing: normal;
  text-transform: none;
  color: var(--color-text-muted);
}

/* school.css gives every third card in a grid the green top rule
   (`.sm-cards > .sm-card:nth-child(3n + 1)`), which is right for a trio of
   different cards and wrong for a list of twenty-two of the same kind: it
   reads as a colour applied at random. Measured at 1440 before this rule: card
   1 green, card 2 grey, and the test centre cards green instead of amber.
   On a hub the colour says what the list is, as the v1 page's own borders did:
   green for an area inside the district, amber for a test centre. Same
   specificity as the rule above, and this sheet loads later. */
.sm-cards > .sm-card.sm-junction--nearby { border-top-color: var(--color-accent); }
.sm-cards > .sm-card.sm-junction--centres { border-top-color: var(--color-star); }

/* The card title is the place name, so it holds the cell. */
.sm-cards a.sm-card h3 { margin-bottom: var(--space-3); }
.sm-cards a.sm-card p { margin-bottom: 0; }

/* Three tickets in a four-track grid left an empty fourth column, because
   auto-fit fits as many 260px tracks as the width allows and then has nothing
   to put in the last one. Measured at 1440: four tracks, three tickets. The
   conformance gate cannot see this, since it counts the children in each row
   and three in one row is not a short row. Three tickets, three columns. */
@media (min-width: 769px) {
  .sm-tickets:has(> :nth-child(3):last-child) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ---------- 3. Why learn here: the four stops ---------- */

/* The road line beside the stops does not paint from the shared rule:
   school.css sets `border-left: var(--road-dash-v)` and that token is a
   repeating gradient, which is not a valid border value, so the whole
   declaration is dropped and the pseudo-element renders 0px wide. Measured,
   not assumed: getComputedStyle(.sm-stops, '::before').borderLeft reads
   "0px none". The conformance gate asks only whether .sm-stops exists, so it
   has been reporting the device present while nothing was drawn.
   Drawn properly here for the hub. The shared fix is in the report; this rule
   comes out when school.css carries it.
   background-image, never the background shorthand, which would reset
   background-size and background-repeat under the gradient. */
.sm-stops::before {
  width: 4px;
  background-image: var(--road-dash-v);
}

/* The reasons run down a dashed road line beside the photograph. The numbered
   roundel is punched out of that line by a ring in the SECTION's ground, and
   this section is Night rather than Road Black, so the ring colour has to
   follow it or the punch-out shows as a dark grey halo. */
.sm-section--deep .sm-stop__num { border-color: var(--color-bg-deep); }

.sm-stops .sm-stop h3 { margin-bottom: var(--space-5); }
.sm-stops .sm-stop:last-child { margin-bottom: 0; }

/* ---------- 4. Prices at display size ---------- */

/* The pack sets a price on a ticket at clamp(44px, 4.6vw, 64px) weight 900 and
   says plainly that real numbers set big are the content, not decoration. The
   shared rule uses the smaller numeral step, which is right for a town page
   where five tickets share a row; three tickets on a hub have the room. */
.sm-ticket__price {
  font-size: clamp(44px, 4.8vw, 68px);
  letter-spacing: var(--ls-tighter);
}

/* The per-lesson line is the figure's own caption, so it sits under it rather
   than a paragraph's distance away. */
.sm-ticket__per { margin-top: var(--space-3); }
.sm-ticket .sm-btn { margin-top: var(--space-12); }
.sm-tickets:has(> :nth-child(3):last-child) .sm-btn { margin-top: auto; }

/* ---------- 5. Other districts ---------- */

/* 21 sibling hubs as pills. They are links, so they get a focus target and a
   hover state, and 44px of height: Rule 15 and the touch target floor. */
.sm-pills { margin-top: var(--space-16); }

a.sm-pill {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-8);
  color: var(--color-text);
  text-decoration: none;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
a.sm-pill:hover {
  background: var(--color-panel);
  border-color: var(--color-accent);
}

/* ---------- 6. Small spacing, hub only ---------- */

/* The breadcrumb opens the hero column, so it needs the hero's own top space
   rather than the section rhythm's. */
.sm-hero .sm-crumb { padding-top: 0; }

/* Rule 20: the line under a section heading is not flush against it. */
.sm-section .sm-lede { margin-top: var(--space-6); }

/* The "view all packages" link closes the pricing section as running copy, not
   as a button: it is a secondary route to a page the buttons above already
   serve. */
.sm-section .sm-prose:last-child { margin-bottom: 0; }
/* ---------- 7. Hero skins ---------- */

/* Finding 1 of the design review: every route in this family shipped one hero
   skin, so neighbouring pages were the same page above the fold. The skin is
   now dealt deterministically per route in
   data/rsa-school/makeover/hero-skin.cjs, and these are the two skins that
   needed work before they read as different HERE.
   The town template gives route and night markup of their own: route puts the
   photograph in an aside frame and night has no backdrop. This family has one
   full-bleed <picture> and no aside, so both skins are composed from the
   element that is already in the markup rather than by adding any.

   Route, the pack's skin B: the photograph stops being a backdrop and becomes
   a framed object on the right, on a green offset block, with the copy held to
   the left half. The 8px chalk keyline and the 28px offset are the pack's own
   numbers, from sections 3.2 and 1/B. */
@media (min-width: 1100px) {
  /* One column first. school.css gives route a 1fr/0.82fr grid for the town
     template's aside, which out-specifies this family's own single-column rule
     and left the copy in a 686px track: with the 52 per cent below that came
     out at 357px and the hero grew 76px taller to wrap it. Measured, not
     assumed. */
  [data-hub-hero].sm-hero--route .sm-hero__grid { grid-template-columns: minmax(0, 1fr); }
  [data-hub-hero].sm-hero--route .sm-hero__grid > div { max-width: 52%; }
  [data-hub-hero].sm-hero--route .sm-hero__photo {
    top: var(--space-28);
    right: var(--space-16);
    bottom: var(--space-28);
    left: 56%;
    z-index: 0;
    border: 8px solid var(--rsa-chalk);
  }
  /* The offset block. ::before is free on this element: school.css draws the
     foot fade on its ::after and nothing else in either sheet touches either
     one, which finding 19 says to check before drawing on a pseudo-element. */
  [data-hub-hero].sm-hero--route .sm-hero__photo::before {
    content: "";
    position: absolute;
    inset: 28px -28px -28px 28px;
    z-index: -1;
    background: var(--color-accent);
  }
  /* A 220px ramp inside a framed photograph is a dark half rather than a weld.
     The frame has an edge of its own, so the fade only has to stop the crop
     reading as a cut. Still above the viewport gate's 150px floor. */
  [data-hub-hero].sm-hero--route .sm-hero__photo::after { height: 160px; }
  /* The copy side goes to near-black, since there is no longer a photograph
     under it to hold down. */
  [data-hub-hero].sm-hero--route::before { background: var(--overlay-panel); }
}

/* Night, the pack's skin C: a slanted photo panel with an 18px green leading
   edge. school.css composes that edge on .sm-hero--night::after, and
   .sm-hero::after, which paints the 6px green rule that closes every hero, is
   declared later at the same specificity. The two merge into one 18px by 6px
   stub: measured on this family and on the night towns, where the closing rule
   is 18px wide and the leading edge does not exist. Both are put back here, the
   edge on the photo wrapper's own ::before, which nothing else uses. The
   collision is in school.css and is in the report as a shared-CSS request, not
   edited here. */
[data-hub-hero].sm-hero--night::after {
  /* display, because school.css hides this pseudo-element below 1100px: that
     was the right call while it carried the skewed leading edge, and it took
     the closing rule with it. Measured at 390px before this line: the night
     hero ended on the photograph with no green rule under it. */
  display: block;
  top: auto;
  right: 0;
  bottom: 0;
  left: 0;
  width: auto;
  height: 6px;
  background: var(--color-accent);
  transform: none;
  z-index: 0;
}
[data-hub-hero].sm-hero--night .sm-hero__photo::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 18px;
  z-index: 1;
  background: var(--color-accent);
}
@media (max-width: 1100px) {
  /* school.css squares the panel up and runs it full width at this size, so
     the leading edge has no edge to lead and goes with the skew. */
  [data-hub-hero].sm-hero--night .sm-hero__photo::before { display: none; }
}

/* The copy keeps the left 48 per cent, which is where the skewed panel's
   leading edge actually lands at 1440 once the skew is counted: measured at
   x 733, not at the 56 per cent the untransformed rule implies. Without this
   the hub's 1.5fr copy track ran 280px under the photograph. */
@media (min-width: 1100px) {
  [data-hub-hero].sm-hero--night .sm-hero__grid { grid-template-columns: minmax(0, 1fr); }
  [data-hub-hero].sm-hero--night .sm-hero__grid > div { max-width: 48%; }
}
