/* =============================================================================
   mh-services.css  -  the SERVICES HUB (Services.razor), CEO Jul 29 2026.

   Services is a section with several services in it. The hub shows one card per
   service; opening a card opens that service's panel. The card is the app's
   standard entity card (white surface, 18px radius, cool hairline, lift on
   hover - the .hs-card / .idcard family) with a per-service accent and the
   dashboard KPI card's hover CTA behaviour ported in: the description fades and
   the "Open ..." line slides up in its place, so the card says what it does only
   when you are actually pointing at it.

   Palette: the canonical cool set from mh-theme.css. No cream, no new colours -
   the two accents are the brand pine and the dashboard's existing plum (the
   Active Volunteers KPI accent), so the hub reads as part of the same system.
   Light + dark parity throughout.
   ============================================================================= */

.mh-app .svc-wrap { max-width: 1180px; }
/* The hub has no page head, so the wrap must fill the canvas for the stage to centre in. */
.mh-app .svc-wrap:has(.svc-stage) { max-width: none; }
/* SAME REASON, for Volunteers (CEO, Aug 8): the shared Coming Soon panel is already
   `place-items:center`, so it WAS centred - inside a 1180px wrap pinned to the left of a
   much wider canvas, which is not where the eye reads centre. Freeing the wrap centres the
   card across the real canvas and leaves the page head where it is, hard against the left.
   Widening the wrap (not adding `margin-inline:auto`) is deliberate: an auto margin would
   have dragged the "Volunteers" heading and its back button into the middle with it.
   Administration / Program / Stub render ComingSoon with no wrap at all, so they were
   never affected and are not touched here. */
.mh-app .svc-wrap:has(.cs-wrap) { max-width: none; }

/* ---- the chooser stage (CEO, Jul 29 2026) ----------------------------------- */
/* The pair sits in the MIDDLE of the canvas rather than tucked under a page head.
   Height arithmetic: the full viewport, less the 70px topbar, less .content's own
   28px top + 40px bottom padding = 138px. Expressed in `--mh-vh`, NEVER bare `vh`:
   the app applies a root `zoom` for Display resolution, which inflates raw vh and
   would push the stage taller than the canvas at every setting but 100%. */
.mh-app .svc-stage {
    min-height: calc(100 * var(--mh-vh) - 138px);
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 30px;
    position: relative;
}
/* A soft pine bloom behind the pair so the centred composition reads as deliberate
   rather than as a half-empty page. Decoration only - no layout, no hit area. */
.mh-app .svc-stage::before {
    content: "";
    position: absolute; left: 50%; top: 50%; translate: -50% -50%;
    width: 900px; height: 460px; max-width: 100%;
    background: radial-gradient(ellipse at center, rgba(78,124,114,.10), transparent 68%);
    pointer-events: none;
}

/* ---- headline --------------------------------------------------------------- */
.mh-app .svc-hero { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.mh-app .svc-hero-t {
    margin: 0;
    font-family: var(--mh-font-head);
    font-size: 38px; font-weight: 700; line-height: 1.1; letter-spacing: -.02em;
    color: var(--mh-ink); text-align: center;
}
/* Short pine bar under the headline - the one flourish, and it carries no words. */
.mh-app .svc-hero-rule {
    width: 54px; height: 3px; border-radius: 999px;
    background: linear-gradient(90deg, var(--mh-green), var(--mh-green-d));
}

/* Grid columns/gap come from the CARD-GRID LAW (.mh-cardgrid in mh-theme.css) -
   2 columns capped, 1 on narrow. Nothing is defined locally EXCEPT the width cap:
   capping the grid and letting margin auto centre it keeps the law's deterministic
   repeat(2, minmax(0,1fr)) intact while pulling the pair into the middle. Two cards
   must never stretch to fill a 1180px canvas - they would read as slabs, not choices. */
.mh-app .svc-grid { align-items: stretch; width: 100%; max-width: 880px; margin-inline: auto; }

/* ---- the service card ------------------------------------------------------ */
/* It is a <button> so it is keyboard-reachable and Enter/Space work for free;
   everything below undoes the browser's button chrome. */
.mh-app .svc-card {
    --a:  var(--mh-green);
    --a2: var(--mh-green-d);
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    text-align: left;
    width: 100%;
    min-width: 0;                 /* grid child must be allowed to shrink */
    font: inherit;
    color: inherit;
    appearance: none;
    cursor: pointer;
    /* GLASS (CEO Jul 29): a translucent pane over the canvas rather than a solid white
       block - the stage's pine bloom shows through it, which is what makes it read as
       glass at all. The frosted look is three layers together: a part-transparent fill,
       a backdrop blur, and a bright hairline that behaves like a lit edge. */
    /* The gloss is a BACKGROUND layer, not a ::after overlay: an overlay would paint on top
       of the icon, description and figures (they are not positioned) and wash them out. */
    background:
        linear-gradient(155deg, rgba(255,255,255,.55) 0%, rgba(255,255,255,.12) 34%, transparent 62%),
        color-mix(in srgb, var(--mh-surface) 58%, transparent);
    backdrop-filter: blur(18px) saturate(1.3);
    -webkit-backdrop-filter: blur(18px) saturate(1.3);
    border: 1px solid rgba(255,255,255,.60);
    border-radius: 20px;
    /* CEO Jul 29: bigger cards, and every element inside them centred. */
    padding: 30px 26px 24px;
    min-height: 300px;
    text-align: center;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.70), 0 18px 40px -22px rgba(33,50,58,.30);
    transition: transform .24s cubic-bezier(.2,.7,.25,1), box-shadow .24s, border-color .2s, background .2s;
    overflow: hidden;
}
/* The accent reads as a hairline along the top edge rather than a block of colour. */
.mh-app .svc-card::before {
    content: "";
    position: absolute; inset: 0 0 auto 0; height: 3px;
    background: linear-gradient(90deg, var(--a), var(--a2));
    opacity: .85;
}
.mh-app .svc-card[data-accent="plum"] { --a: #8E6E89; --a2: #6B4F67; }

/* HOVER = ZOOM IN (CEO Jul 29). The card scales up under the pointer and returns to its
   exact resting size the moment the pointer leaves - one transform property, so there is
   no state to get stuck in. 1.045 on a 432px card grows it ~19px, well inside the 16px
   gutter plus the stage's slack, so a zoomed card never touches its neighbour. The lift
   is folded into the same transform: two properties animating the same thing would fight. */
.mh-app .svc-card:hover,
.mh-app .svc-card:focus-visible {
    transform: translateY(-4px) scale(1.045);
    z-index: 2;                        /* the zoomed pane rides above its sibling */
    border-color: color-mix(in srgb, var(--a) 55%, rgba(255,255,255,.6));
    background:
        linear-gradient(155deg, rgba(255,255,255,.68) 0%, rgba(255,255,255,.18) 34%, transparent 62%),
        color-mix(in srgb, var(--mh-surface) 70%, transparent);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.85), 0 30px 60px -24px rgba(33,50,58,.38);
}
.mh-app .svc-card:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--a) 45%, transparent), 0 30px 60px -24px rgba(33,50,58,.38); }
.mh-app .svc-card:active { transform: translateY(-2px) scale(1.02); }

/* ---- the logo tile, centred ------------------------------------------------- */
/* The tile is the card's anchor now: centred at the top and much larger (72px vs 46px),
   so each service reads as a mark first and a word second. The state chip leaves this row
   entirely and pins to the card's top-right corner, which is the only way the tile can sit
   on the TRUE centre line - sharing a flex row with a chip would always push it off. */
.mh-app .svc-top { display: block; }
/* A full CIRCLE, not a rounded square (CEO Jul 29), wearing a second ring outside it:
   a translucent gap first, then a thin accent hairline - the same two-step halo the app
   already uses on household avatars (.idc-ph), so this reads as part of the set. Both rings
   are box-shadows, so they cost no layout and cannot shift the icon off the centre line. */
.mh-app .svc-ic {
    width: 74px; height: 74px; border-radius: 50%; margin: 0 auto;
    display: grid; place-items: center; color: #fff;
    background: linear-gradient(135deg, var(--a), var(--a2));
    box-shadow:
        0 0 0 5px rgba(255,255,255,.55),
        0 0 0 6.5px color-mix(in srgb, var(--a) 38%, transparent),
        0 10px 22px -8px color-mix(in srgb, var(--a) 70%, transparent);
    transition: transform .24s cubic-bezier(.2,.7,.25,1), box-shadow .24s cubic-bezier(.2,.7,.25,1);
}
.mh-app .svc-ic svg { width: 34px; height: 34px; }
/* On hover the halo opens up a little. No rotation: a circle rotating reads as a wobble. */
.mh-app .svc-card:hover .svc-ic,
.mh-app .svc-card:focus-visible .svc-ic {
    box-shadow:
        0 0 0 6px rgba(255,255,255,.70),
        0 0 0 8px color-mix(in srgb, var(--a) 52%, transparent),
        0 14px 28px -8px color-mix(in srgb, var(--a) 70%, transparent);
}

.mh-app .svc-chip {
    position: absolute; top: 18px; right: 18px;
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 11px; font-weight: 800; letter-spacing: .3px;
    padding: 5px 11px; border-radius: 999px; white-space: nowrap;
}
.mh-app .svc-chip.is-live { color: var(--mh-green-d); background: rgba(78,124,114,.13); }
.mh-app .svc-chip.is-soon { color: var(--mh-warning-d); background: rgba(216,155,61,.16); }
.mh-app .svc-chip-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ---- name + description ----------------------------------------------------- */
/* NOTHING here swaps text on hover. The first cut of this card copied the dashboard's
   .kpi-cta idea - fade the description out, fade an "Open ..." line in - and it produced
   exactly the defect the CEO reported: the two strings shared a box, so mid-transition both
   were painted and the card read as garbled text. Worse, the absolutely-positioned CTA was
   pinned with a magic `top` that landed on the NAME (measured: name 258-288, CTA 266-288),
   so the collision was permanent rather than just during the fade. The name and description
   are now permanent, and the only hover affordance is the arrow - not text, so it cannot
   collide with anything. Lesson: never cross-fade two different strings in one box. */
/* The name is CENTRED and UPPERCASE (CEO Jul 29). Nothing else shares this row any more -
   the hover arrow that used to sit at its right edge was removed - so the title is centred
   with no counterweight to correct for. The inline padding just keeps a long service name
   off the card's edges; it ellipsises rather than touching them. */
.mh-app .svc-namerow {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    padding-inline: 20px; margin-top: 20px;
}
.mh-app .svc-name {
    position: relative;           /* anchors the hover underline (::after) */
    font-family: var(--mh-font-head);
    font-size: 19px; font-weight: 800; color: var(--mh-ink);
    text-transform: uppercase; letter-spacing: .07em;
    padding-bottom: 7px;          /* the underline sits in this space, inside the clip box */
    min-width: 0;                 /* let a long service name ellipsis, not overflow the card */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    transition: color .22s ease;
}
/* EXACTLY two rows, on both cards (CEO Jul 29). The height is FIXED rather than a minimum,
   and the text is clamped to 2 lines, so neither a longer sentence nor a wider glyph set can
   push the divider below it out of step with the other card. Keep copy under ~68 chars: the
   clamp protects the layout, but it protects it by hiding the overflow. */
.mh-app .svc-desc {
    font-size: 13.5px; line-height: 1.55; color: var(--mh-muted);
    margin: 10px auto 0; max-width: 34ch;
    height: calc(2 * 1.55 * 13.5px);
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}

/* ---- stats ------------------------------------------------------------------ */
/* Pinned to the bottom via margin-top:auto so both cards' stat rows sit on the
   same line however long the description runs (card-grid law, footer rule). */
/* THE DIVIDER MUST LAND ON THE SAME LINE ON BOTH CARDS (CEO Jul 29).
   It is this block's border-top, and the block is bottom-pinned (margin-top:auto), so its
   y is `card bottom - padding - this height`. The cards are already equal height, so the
   one thing left to equalise is THIS height - hence the fixed min-height, which the
   three-figure grid and the single "not started yet" line both honour. Previously the
   figures block was ~20px taller than the sentence and the two rules sat out of step. */
.mh-app .svc-stats {
    margin-top: auto;
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
    align-content: center; min-height: 74px;
    padding-top: 18px; border-top: 1px solid color-mix(in srgb, var(--mh-line-cool) 75%, transparent);
    text-align: center;
}
.mh-app .svc-stats > div { min-width: 0; display: flex; flex-direction: column; gap: 5px; align-items: center; }
.mh-app .svc-stats .k {
    font-size: 9.5px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase;
    color: var(--mh-muted);
}
.mh-app .svc-stats .v {
    font-size: 19px; font-weight: 700; color: var(--mh-ink);
    font-variant-numeric: tabular-nums;
    transition: color .2s;
}
.mh-app .svc-card:hover .svc-stats .v { color: var(--a); }
/* The not-started card has no numbers to show - it says so instead of inventing any. It
   keeps .svc-stats' fixed min-height so its divider lines up with the other card's. */
.mh-app .svc-stats-empty {
    display: grid; place-items: center; grid-template-columns: minmax(0, 1fr);
    font-size: 12.5px; font-weight: 600; color: var(--mh-muted);
}

/* ---- hover affordance: the TITLE itself ------------------------------------- */
/* The floating arrow is gone (CEO Jul 29). The service name is now the affordance: on hover
   it takes the card's own logo colour and an underline wipes in beneath it, left to right.
   The rule is a pseudo-element scaled on the X axis, so only `transform` animates - width
   or background-position would relayout or band. It lives INSIDE .svc-name's padding box
   because .svc-name clips its overflow for the ellipsis; a negative offset would be cut off.
   Note this changes colour and adds a line - it never swaps the WORDS (see .svc-namerow).

   The rule is `var(--a)` - the SAME logo colour the title turns and the icon is built from
   (pine on Housing Subsidy, plum on Volunteers), so each card hovers in one colour rather
   than two. Being the accent, it needs no dark-mode override: both accents are fixed brand
   colours that hold up on the white pane and the dark one. */
.mh-app .svc-name::after {
    content: "";
    position: absolute; left: 0; right: 0; bottom: 0; height: 2px; border-radius: 2px;
    background: var(--a);
    transform: scaleX(0); transform-origin: left center;
    transition: transform .34s cubic-bezier(.22,.68,.24,1);
}
.mh-app .svc-card:hover .svc-name,
.mh-app .svc-card:focus-visible .svc-name { color: var(--a); }
.mh-app .svc-card:hover .svc-name::after,
.mh-app .svc-card:focus-visible .svc-name::after { transform: scaleX(1); }

/* ---- the Volunteers surface's back-to-hub button ---------------------------- */
.mh-app .svc-phead { margin-bottom: 18px; }
.mh-app .svc-back {
    display: inline-flex; align-items: center; gap: 4px;
    margin-bottom: 10px; padding: 6px 12px 6px 8px;
    font-size: 12.5px; font-weight: 700; color: var(--mh-green-d);
    background: rgba(78,124,114,.10); border: 1px solid transparent; border-radius: 999px;
    cursor: pointer; transition: background .15s, border-color .15s;
}
.mh-app .svc-back:hover { background: rgba(78,124,114,.17); border-color: var(--mh-green); }
.mh-app .svc-back svg { width: 15px; height: 15px; }

/* ---- dark ------------------------------------------------------------------- */
body.dark .mh-app .svc-hero-t { color: #eef2f1; }
/* The bloom has to lift off a dark canvas, so it warms slightly instead of fading out. */
body.dark .mh-app .svc-stage::before {
    background: radial-gradient(ellipse at center, rgba(78,124,114,.20), transparent 68%);
}
/* Glass in dark: the pane darkens instead of brightening, and the lit edge drops to a
   whisper - a .60 white hairline that reads as "lit" on #E8EBF0 reads as a scratch on #151C1A. */
body.dark .mh-app .svc-card {
    background:
        linear-gradient(155deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,.03) 34%, transparent 62%),
        color-mix(in srgb, var(--mh-surface) 62%, transparent);
    border-color: rgba(255,255,255,.10);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 18px 40px -22px rgba(0,0,0,.55);
}
body.dark .mh-app .svc-card:hover,
body.dark .mh-app .svc-card:focus-visible {
    background:
        linear-gradient(155deg, rgba(255,255,255,.14) 0%, rgba(255,255,255,.05) 34%, transparent 62%),
        color-mix(in srgb, var(--mh-surface) 78%, transparent);
    border-color: color-mix(in srgb, var(--a) 60%, transparent);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.10), 0 30px 60px -24px rgba(0,0,0,.66);
}
/* The icon's inner halo ring is a white gap on light; in dark it has to be a dark gap. */
body.dark .mh-app .svc-ic {
    box-shadow:
        0 0 0 5px rgba(255,255,255,.08),
        0 0 0 6.5px color-mix(in srgb, var(--a) 46%, transparent),
        0 10px 22px -8px rgba(0,0,0,.5);
}
body.dark .mh-app .svc-card:hover .svc-ic,
body.dark .mh-app .svc-card:focus-visible .svc-ic {
    box-shadow:
        0 0 0 6px rgba(255,255,255,.12),
        0 0 0 8px color-mix(in srgb, var(--a) 62%, transparent),
        0 14px 28px -8px rgba(0,0,0,.55);
}
body.dark .mh-app .svc-name { color: #eef2f1; }
body.dark .mh-app .svc-stats .v { color: #eef2f1; }
body.dark .mh-app .svc-chip.is-live { color: color-mix(in srgb, var(--mh-green) 60%, #fff); background: color-mix(in srgb, var(--mh-green) 24%, transparent); }
body.dark .mh-app .svc-chip.is-soon { color: #E8BE7A; background: rgba(216,155,61,.20); }
body.dark .mh-app .svc-back { color: color-mix(in srgb, var(--mh-green) 60%, #fff); background: color-mix(in srgb, var(--mh-green) 20%, transparent); }

/* ---- narrow ----------------------------------------------------------------- */
@media (max-width: 720px) {
    /* Stacked cards are taller than the canvas - stop forcing a centre it cannot hold. */
    .mh-app .svc-stage { min-height: 0; justify-content: flex-start; padding-top: 8px; }
    .mh-app .svc-hero-t { font-size: 28px; }
}
/* Touch has no hover, so the title's colour + underline never fire there. The card's own
   name, figures and chip already say what it is; nothing is hidden behind hover. */
