/* 04-public.css - public marketing pages

   NUMBERED CASCADE. File order IS cascade order. These files are linked from
   App.razor in numeric order and nothing else, so a rule in a later file wins
   over the same-specificity rule in an earlier one.

   APPEND a new file in sequence. Never insert one alphabetically or renumber
   an existing one: both silently change which rule wins on every page.

   07-admin.css is the exception and is linked from AdminLayout only, so a
   member of the public downloads zero bytes of back-office CSS. That is why
   this sequence stops at 04.

   ---------------------------------------------------------------------------
   ONLY COMPOSITION SHARED BY MORE THAN ONE PUBLIC PAGE BELONGS HERE.

   Anything used by exactly one page goes in wwwroot/css/pages/<page>.css and
   is linked from that page's own <HeadContent>, so the other thirty pages do
   not download it. If you are about to add a rule here, first check that a
   second page really uses it.

   The pieces below are shared by at least two of: home, about, the eight
   service pages, the four programme pages, contact, the service-area hub and
   its three town pages.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   PAGE HERO. Home has the full-bleed version; every other page uses the plain
   title block. Both give the h1 a lead beneath it and nothing else, because
   law 2 allows one primary action per screen and the hero is where it lives.
   =========================================================================== */

.page-hero {
    /* 32px above, not 80px. The breadcrumb directly above this is already a
       band of space, so a full section's worth of padding under it stacked two
       gaps into one and left roughly 110px of nothing between "Home / About"
       and the page title. Sections still breathe; this one was breathing
       twice. */
    padding-block: var(--space-5) var(--space-7);
    border-bottom: 1px solid var(--rule);
}

.page-hero__inner {
    width: var(--container-narrow);
    margin-inline: auto;
}

.page-hero .lead {
    margin-top: var(--space-4);
}

.page-hero__actions {
    margin-top: var(--space-6);
}

/* ===========================================================================
   BREADCRUMBS. Every page below the top level. Rendered as a real ordered
   list inside a labelled nav, and the current page is plain text rather than
   a link to itself.
   =========================================================================== */

.breadcrumbs {
    padding-block: var(--space-4);
    font-size: var(--fs-small);
}

/* THE FIRST BAND AFTER A BREADCRUMB DOES NOT NEED A FULL SECTION'S PADDING.

   Every section carries 80px above it, which is the rhythm the rest of the
   page is built on and is right between two bands of content. Directly under
   a breadcrumb it is wrong: the breadcrumb is already a band of space, so the
   two stack and leave about 140px of nothing between "Home / Trauma therapy"
   and the page title, on every page below the top level. The title is the
   thing somebody came to read.

   This is deliberately a sibling selector rather than :first-child, so it
   applies to whatever the page puts first and cannot be defeated by wrapping
   the content in one more element. */
.breadcrumbs + .section,
.breadcrumbs + .page-hero {
    padding-top: var(--space-5);
}

.breadcrumbs ol {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    width: var(--container);
    margin-inline: auto;
}

.breadcrumbs li {
    max-width: none;
    color: var(--ink-muted);
}

.breadcrumbs li + li::before {
    content: "/";
    margin-right: var(--space-2);
    color: var(--rule-strong);
}

/* ===========================================================================
   PROSE. The long-form reading column, used by every service page, every
   programme page, the policies and the blog. --container-narrow throughout
   (DESIGN.md section 6).

   The measure is enforced here rather than page by page: a full-width
   paragraph is a bug, and this is a site read by anxious people at 11pm.
   =========================================================================== */

.prose {
    width: var(--container-narrow);
    margin-inline: auto;
}

.prose > * + * {
    margin-top: var(--space-4);
}

.prose h2 {
    margin-top: var(--space-7);
}

.prose h3 {
    margin-top: var(--space-6);
}

.prose ul,
.prose ol {
    padding-left: var(--space-5);
    max-width: var(--measure);
}

.prose li + li {
    margin-top: var(--space-2);
}

.prose ul {
    list-style: disc;
}

.prose ol {
    list-style: decimal;
}

/* ===========================================================================
   MEDIA. A photograph beside a block of text, on more than half the pages.
   Every image is a Picture component with explicit width and height, so the
   only thing this rule does is place it.
   =========================================================================== */

.media {
    display: grid;
    gap: var(--space-6);
    align-items: center;
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 860px) {
    .media {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-7);
    }

    /* The photograph on the right, text on the left, without reordering the
       DOM: the text is first in source on every viewport, which is what a
       screen reader and a narrow phone both want. */
    .media--reverse > :first-child {
        order: 2;
    }
}

.media__figure {
    margin: 0;
}

.media__figure img {
    width: 100%;
    border-radius: var(--radius-card);
}

.media__caption {
    margin-top: var(--space-3);
    font-size: var(--fs-small);
    color: var(--ink-muted);
    max-width: 46ch;
}

/* ===========================================================================
   NUMBERED STEPS. The three-step "how it works" on the home page and the
   first-appointment sequence on the contact and service pages.
   =========================================================================== */

.steps {
    list-style: none;
    counter-reset: step;
    display: grid;
    gap: var(--space-6);
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 860px) {
    .steps {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--gutter);
    }
}

.steps li {
    counter-increment: step;
    max-width: none;
}

/* The number is generated, but the step is ALSO named in the markup, so the
   ordering is never carried by a CSS counter alone. */
.steps li::before {
    content: counter(step);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    margin-bottom: var(--space-4);
    border-radius: 50%;
    background-color: var(--bg-sage);
    color: var(--ink-strong);
    font-family: var(--font-display);
    font-size: var(--fs-h3);
}

.section--sage .steps li::before,
.insurer-strip .steps li::before {
    background-color: var(--bg-raised);
}

/* ===========================================================================
   DEFINITION LISTS. Credentials on the about page, session practicalities on
   the service pages, fees on the insurance page.
   =========================================================================== */

.deflist {
    display: grid;
    gap: var(--space-4);
    max-width: var(--measure);
}

.deflist div {
    display: grid;
    gap: var(--space-1);
}

.deflist dt {
    font-weight: 600;
    color: var(--ink-strong);
}

.deflist dd {
    margin: 0;
    color: var(--ink);
}

@media (min-width: 560px) {
    .deflist div {
        grid-template-columns: minmax(9rem, 14rem) minmax(0, 1fr);
        gap: var(--space-4);
    }
}

/* ===========================================================================
   DATA TABLE. Hours on the contact page, the drive-time table on the
   service-area hub, the fee table on the insurance page. Scrolls inside its
   own box rather than pushing the page sideways, because text at 200% must
   not produce a horizontal scrollbar (DESIGN.md section 7).
   =========================================================================== */

/* THE CAP IS min(), NOT A BARE ch VALUE.

   overflow-x: auto only clips at the wrapper's OWN width, so a wrapper that
   is itself wider than the viewport pushes the document sideways instead of
   scrolling inside itself. --measure is in ch, so at 200% text 62ch is over
   1,100px and the cap stopped capping anything: /insurance-and-fees rendered
   an 895px fee table and shoved the whole "why it matters" column off the
   screen, on the page that answers "do you take my insurance".

   min(--measure, 100%) is the fix, and it is the reason this rule now works
   at both text sizes rather than only the one CI used to check. */
.table-wrap {
    overflow-x: auto;
    max-width: min(var(--measure), 100%);
}

.data-table {
    width: 100%;
    font-size: var(--fs-small);
    text-align: left;
}

/* THE CAPTION IS PROSE, SO IT MUST NOT NEED SCROLLING TO READ.

   A caption is as wide as its table by default, and the table here is 895px
   at 200% text inside a 310px scroll box, so the caption was clipped after
   about four words and the rest of the sentence was off to the right. The
   TABLE may need two-dimensional scrolling, and WCAG 1.4.10 says so in as
   many words; the sentence explaining the table may not.

   Capped to the scroll box's own width rather than the table's, and stuck to
   its left edge so it stays put while the rows scroll under it. The cap is
   the same expression the wrapper uses, so the two cannot drift apart.
   display stays table-caption: setting it to block moves the caption below
   the header row. */
.data-table caption {
    position: sticky;
    left: 0;
    width: max-content;
    max-width: min(var(--measure), calc(100vw - 2.5rem));
    text-align: left;
    color: var(--ink-muted);
    padding-bottom: var(--space-3);
}

.data-table th,
.data-table td {
    padding: var(--space-3) var(--space-4) var(--space-3) 0;
    border-bottom: 1px solid var(--rule);
    vertical-align: baseline;
}

.data-table thead th {
    color: var(--ink-strong);
    font-weight: 600;
    border-bottom-color: var(--rule-strong);
}

.data-table tbody th {
    font-weight: 500;
    white-space: nowrap;
}

/* ===========================================================================
   LINK LIST. The service index, the programme index, related links at the
   foot of a service page.
   =========================================================================== */

.link-list {
    list-style: none;
    display: grid;
    gap: var(--space-2);
    max-width: var(--measure);
}

.link-list li {
    max-width: none;
}

.link-list a {
    display: inline-block;
    padding-block: var(--space-2);
    font-weight: 500;
}

/* ===========================================================================
   PHOTOGRAPHS.

   Everything below exists because of one review note: "the WordPress site
   honestly looked better cause it was fleshed out with images and content".
   It was right. Nine professional photographs of this building were sitting in
   wwwroot/img/photos and the site used two of them, and every service page was
   five hundred words of prose with nothing to look at. Calm editorial does not
   mean empty. It means a magazine, and a magazine has pictures.

   Four shapes, and no page needs a fifth:

     .prose-figure   one photograph in the 760px reading column
     .photo-band     one photograph edge to edge, the full-bleed moment
     .photo-grid     a static gallery of rooms, two or three across
     .pull-quote     a line worth stopping on, usually the practice's own

   NONE OF THEM MOVE. There is no carousel here and there will not be one:
   DESIGN.md law 4 rules out auto-moving content because motion is a trigger
   for a real share of this audience, and a slider also hides most of its own
   content from a crawler and from anybody who never swipes. A grid of six
   photographs shows six photographs.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   A PHOTOGRAPH IN THE READING COLUMN. Service pages, program pages, about.
   Full column width, captioned, and never floated: a float here would set a
   400px paragraph beside a picture on a page that anxious people read.
   --------------------------------------------------------------------------- */

.prose-figure {
    margin: var(--space-6) 0 0;
}

.prose-figure img {
    display: block;
    width: 100%;
    border-radius: var(--radius-card);
}

/* ---------------------------------------------------------------------------
   FULL BLEED. Edge to edge, so it is placed OUTSIDE .container as a direct
   child of its section and the section carries no inline padding.

   The aspect ratio is declared in CSS rather than left to the file, so the box
   is fully determined before a byte arrives and the band costs nothing in
   layout shift. It is close to square on a phone, where a 24:9 letterbox would
   be 146px of nothing, and a proper band on a wide screen.
   --------------------------------------------------------------------------- */

.photo-band {
    margin: 0;
    overflow: hidden;
}

/* THE PHONE BOX IS NARROWER THAN THE PICTURE AND THE DESKTOP BOX IS WIDER,
   AND THAT DIFFERENCE IS THE WHOLE OF THE CROP LOGIC BELOW.

   The one frame this band carries has a wooden joke sign at its right edge
   that the shot already cuts in half, and image-manifest.md says to crop it
   out rather than show it half-read. object-fit can only crop the axis its box
   is SHORT on:

     phone     5:4 is narrower than the 1.57 photograph, so cover crops
               horizontally and object-position: left throws away the right
               fifth, which is exactly the fifth with the sign in it. The
               painted words are top left and survive whole.
     desktop   24:9 is wider than the photograph, so cover crops vertically
               and cannot touch the right edge at all. There the picture is
               drawn 118% wide inside a frame that is overflow: hidden, which
               clips the same fifth off. Nothing reaches the document, so this
               does not show up as a reflow failure.

   Splitting it this way also means the phone's sizes attribute is honest:
   100vw really is 100vw there, so a 390px screen fetches the 1200 derivative
   rather than the 1800 it would need for a 118vw box. That is 29KB. */
.photo-band img {
    display: block;
    width: 100%;
    aspect-ratio: 5 / 4;
    object-fit: cover;
    object-position: left center;
}

@media (min-width: 860px) {
    .photo-band img {
        aspect-ratio: 24 / 9;
        object-position: left top;
    }

    .photo-band--trim-right img {
        width: 118%;
        max-width: none;
    }
}

.photo-band figcaption {
    width: var(--container);
    margin: var(--space-3) auto 0;
    font-size: var(--fs-small);
    color: var(--ink-muted);
}

/* ---------------------------------------------------------------------------
   THE GALLERY. Rooms, captioned honestly, as a plain list of pictures.

   Tiles share one aspect ratio so the grid reads as a set rather than as
   whatever the crops happened to be. The photographs are 1200x766, which is
   1.57, so a 3:2 tile trims about four percent off the height of each and
   nothing that matters.
   --------------------------------------------------------------------------- */

.photo-grid {
    list-style: none;
    display: grid;
    gap: var(--space-5);
    grid-template-columns: minmax(0, 1fr);
    margin-top: var(--space-6);
}

@media (min-width: 560px) {
    .photo-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* THE SIX-UP GALLERY IS TWO ACROSS ON A PHONE, NOT ONE.

   One across is right for the home page's four rooms, where each picture is
   doing the reassuring on its own. It is wrong for the about page's six, which
   are a contact sheet of a building: two across shows four rooms at a glance
   with their captions, and it cuts what a phone downloads to read the page by
   about half, because a 48vw tile picks the 768px derivative where a 100vw
   tile picks the 1200. */
.photo-grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
}

@media (min-width: 860px) {
    .photo-grid--3 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: var(--space-5);
    }
}

.photo-grid li {
    max-width: none;
}

/* Inside the reading column the gallery is still a ul, and .prose ul wins on
   specificity: it would give the tiles a disc marker, a 32px indent and a 62ch
   cap. A measure is for prose. Six photographs are not prose.

   These two overrides have to live HERE rather than beside the components they
   belong to, because file order is cascade order and .prose ul is declared in
   this file. The same selector in 03-components.css ties on specificity and
   loses on order, which is a silent no-op. */
.prose .photo-grid,
.prose .insurer-logos {
    list-style: none;
    padding-left: 0;
    max-width: none;
}

.photo-grid figure {
    margin: 0;
}

.photo-grid img {
    display: block;
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    border-radius: var(--radius-card);
}

/* The same right-edge trim as the band, for the one frame that needs it,
   wherever that frame appears. A 4:3 box is narrower than the 1.57
   photograph, so here object-fit CAN do the crop, and left alignment keeps the
   painted tree and loses the joke sign the shot cuts in half.

   The selector is spelled three ways because .photo-grid img and
   .prose-figure img are both one class plus one type, and a bare class would
   lose the aspect-ratio to whichever of them the picture is sitting in. */
.photo--trim-right,
.photo-grid img.photo--trim-right,
.prose-figure img.photo--trim-right {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    object-position: left center;
}

.photo-grid figcaption {
    margin-top: var(--space-3);
    font-size: var(--fs-small);
    color: var(--ink-muted);
}

/* ---------------------------------------------------------------------------
   PULL QUOTE. Used for the practice's own words: the tree painted on the
   waiting-room wall, and the welcome sign inside the front door. Both are in
   docs/content/source-copy.md as verified, both are theirs, and both are
   better than anything a copywriter would have written for them.

   A rule on the leading edge rather than typographic quote marks, because a
   large opening quote set in Fraunces at a heading size is a decoration that
   then has to be hidden from a screen reader, and this is real quoted text.
   --------------------------------------------------------------------------- */

.pull-quote {
    margin-block: var(--space-6);
    padding-left: var(--space-5);
    border-left: 4px solid var(--sage);
    max-width: var(--measure);
    font-family: var(--font-display);
    font-size: var(--fs-h3);
    line-height: var(--lh-heading);
    color: var(--ink-strong);
}

.pull-quote p {
    max-width: none;
}

.pull-quote footer {
    margin-top: var(--space-3);
    font-family: var(--font-body);
    font-size: var(--fs-small);
    line-height: var(--lh-body);
    color: var(--ink-muted);
}

.section--deep .pull-quote,
.cta-band--deep .pull-quote {
    border-left-color: var(--teal);
    color: var(--ink-on-deep);
}

.section--deep .pull-quote footer {
    color: var(--ink-on-deep);
}

/* ---------------------------------------------------------------------------
   THE PERSON. Ann Marie's portrait beside her name, her credentials and one
   line about her. High on the home page, and leading the about page.

   A therapy practice with no face on it is the largest conversion problem a
   therapy practice can have. Every directory this one competes with leads with
   a portrait, because choosing a counselor is choosing a person and people
   decide by looking at them.

   THE PORTRAIT COLUMN IS IN PIXELS AND THAT IS DELIBERATE. Everything else on
   this site sizes in rem so it grows with the reader's text setting. This one
   must not: the file is 320x400 native, recovered from her own old profile,
   and there is no wider one. A rem column doubles to 400px at 200% text and
   upscales a photograph of somebody's face by a quarter, which looks exactly
   like what it is. The text beside it grows normally and the picture stays
   sharp.
   --------------------------------------------------------------------------- */

.person {
    display: grid;
    gap: var(--space-5);
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
}

@media (min-width: 560px) {
    .person {
        grid-template-columns: 200px minmax(0, 1fr);
        gap: var(--space-6);
    }
}

.person__portrait {
    margin: 0;
    width: 200px;
    max-width: 100%;
}

.person__portrait img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--radius-card);
}

.person__name {
    margin-top: 0;
}

.person__role {
    margin-top: var(--space-2);
    color: var(--ink-muted);
    font-size: var(--fs-small);
}

.person__body > * + * {
    margin-top: var(--space-4);
}
