/* ============================================================================
   Modibbo Girei — public site
   ----------------------------------------------------------------------------
   The pages the family and the wider public browse: home, the family tree,
   member profiles, heritage statistics, about.

   Shares tokens.css, base.css and components.css with the portal, so the two
   surfaces are recognisably the same product. What differs is proportion: the
   portal is dense because it is operated, the public site is open because it is
   read.

   Replaces the "RS education" template inherited from the copied AGGA site —
   39 MB of stock imagery, five icon fonts, Owl Carousel, Slick, WOW.js,
   Magnific Popup, Isotope and Modernizr, for a handful of pages.
   ============================================================================ */

/* ============================================================================
   Header
   ============================================================================ */
.s-header {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    background: color-mix(in srgb, var(--surface-page) 85%, transparent);
    backdrop-filter: saturate(1.5) blur(10px);
    border-bottom: 1px solid var(--border-subtle);
}
.s-header__inner {
    display: flex;
    align-items: center;
    gap: var(--space-6);
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-3) var(--space-6);
}
.s-header__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

.s-brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    text-decoration: none;
    color: var(--text-primary);
    flex: none;
}
.s-brand:hover { color: var(--text-primary); text-decoration: none; }
.s-brand__mark {
    /* Was a 10px CSS dot; now the family tree mark (logo.svg). */
    width: 24px;
    height: 24px;
    display: block;
    flex: none;
}
.s-brand__text {
    font-size: var(--fs-md);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--tracking-tight);
}

.s-nav { display: flex; align-items: center; gap: var(--space-1); }
.s-nav__link {
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    text-decoration: none;
    white-space: nowrap;
}
.s-nav__link:hover { background: var(--surface-hover); color: var(--text-primary); text-decoration: none; }
.s-nav__link[aria-current="page"] { color: var(--accent-text); background: var(--accent-subtle); }

.s-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px; height: 34px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}
.s-icon-btn:hover { background: var(--surface-hover); color: var(--text-primary); }
.s-icon-btn:focus-visible { outline: none; box-shadow: var(--ring-focus); }

/* Visitors-this-week pill. Quiet on purpose: it sits beside the sign-in button
   and must not compete with it. The number carries the weight; the words are
   secondary, and the dot does the work of saying "people". */
.s-viewers {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    height: 34px;                       /* matches .s-icon-btn, so the row is even */
    padding: 0 var(--space-3);
    border-radius: var(--radius-full);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-size: var(--fs-sm);
    white-space: nowrap;
    cursor: default;
    user-select: none;
}
.s-viewers__dot {
    width: 6px; height: 6px;
    border-radius: var(--radius-full);
    background: var(--accent);
    flex: none;
}
.s-viewers__n {
    color: var(--text-primary);
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
    .s-header__inner { flex-wrap: wrap; gap: var(--space-3); padding: var(--space-3) var(--space-4); }
    .s-nav { order: 3; width: 100%; overflow-x: auto; scrollbar-width: none; }
    .s-nav::-webkit-scrollbar { display: none; }

    /* Row one is brand + actions + sign-in on a narrow screen, which is already
       tight. Drop the words and keep the dot and the number.
       Spelled out rather than reusing .sr-only from base.css because that class
       applies unconditionally and this must only hide below 720px — the words
       are visible again above it. Hidden this way rather than with display:none
       so the figure never reaches a screen reader as a bare "47". */
    .s-viewers { padding: 0 var(--space-2); gap: 6px; }
    .s-viewers__label {
        position: absolute;
        width: 1px; height: 1px;
        padding: 0; margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}

/* ============================================================================
   Page furniture
   ============================================================================ */
.s-wrap {
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-10) var(--space-6);
}
.s-wrap--narrow { max-width: 860px; }

.s-section { padding-block: var(--space-12); }
.s-section + .s-section { border-top: 1px solid var(--border-subtle); }

.s-section__head { margin-bottom: var(--space-8); }
.s-eyebrow {
    display: block;
    margin-bottom: var(--space-2);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--accent-text);
}
.s-section__title {
    margin: 0;
    font-size: var(--fs-2xl);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--tracking-tight);
    text-wrap: balance;
}
.s-section__lede {
    margin: var(--space-3) 0 0;
    color: var(--text-secondary);
    font-size: var(--fs-md);
    max-width: 60ch;
}

/* ============================================================================
   Hero
   ----------------------------------------------------------------------------
   No stock photography and no carousel. The subject of this site is a lineage,
   so the hero draws one: concentric rings spreading from a single point.
   ============================================================================ */
.s-hero {
    position: relative;
    overflow: hidden;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--surface-page);
}
.s-hero::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1200px;
    height: 1200px;
    transform: translate(-50%, -50%);
    background:
        radial-gradient(circle, transparent 0 148px, var(--border-subtle) 148px 149px, transparent 149px),
        radial-gradient(circle, transparent 0 248px, var(--border-subtle) 248px 249px, transparent 249px),
        radial-gradient(circle, transparent 0 378px, var(--border-subtle) 378px 379px, transparent 379px),
        radial-gradient(circle, transparent 0 528px, var(--border-subtle) 528px 529px, transparent 529px);
    opacity: 0.7;
    pointer-events: none;
}
.s-hero__inner {
    position: relative;
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-20) var(--space-6);
    text-align: center;
}
.s-hero__title {
    margin: 0 auto var(--space-4);
    max-width: 18ch;
    font-size: var(--fs-4xl);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
    letter-spacing: var(--tracking-tight);
    text-wrap: balance;
}
.s-hero__lede {
    margin: 0 auto var(--space-8);
    max-width: 54ch;
    color: var(--text-secondary);
    font-size: var(--fs-md);
}
.s-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    justify-content: center;
}
@media (max-width: 640px) {
    .s-hero__inner { padding: var(--space-12) var(--space-4); }
    .s-hero__title { font-size: var(--fs-2xl); }
}

/* ============================================================================
   Figures strip
   ============================================================================ */
.s-figures {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-6);
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-8) var(--space-6);
    border-top: 1px solid var(--border-subtle);
}
.s-figure { text-align: center; }
.s-figure__value {
    display: block;
    font-size: var(--fs-2xl);
    font-weight: var(--fw-semibold);
    font-variant-numeric: tabular-nums;
    letter-spacing: var(--tracking-tight);
}
.s-figure__label {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--fs-xs);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
}

/* ============================================================================
   Carousel — members of the day
   ----------------------------------------------------------------------------
   CSS scroll-snap, not a library. Owl Carousel needed jQuery and a dozen
   data-* attributes to do less than this; scroll-snap gives native momentum,
   working scrollbars, and keyboard scrolling for free.
   ============================================================================ */
.s-carousel { position: relative; }
.s-carousel__track {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(240px, 1fr);
    gap: var(--space-4);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    padding-bottom: var(--space-3);
    scrollbar-width: none;
}
.s-carousel__track::-webkit-scrollbar { display: none; }
.s-carousel__track > * { scroll-snap-align: start; }

@media (min-width: 900px) {
    .s-carousel__track { grid-auto-columns: minmax(0, 1fr); overflow-x: visible; }
}

.s-carousel__controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
}
@media (min-width: 900px) { .s-carousel__controls { display: none; } }

.s-carousel__dot {
    width: 7px; height: 7px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--border-strong);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out),
                width var(--duration-fast) var(--ease-out);
}
.s-carousel__dot[aria-current="true"] { background: var(--accent); width: 20px; }

/* ---- Member card --------------------------------------------------------- */
.s-member {
    display: flex;
    flex-direction: column;
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: transform var(--duration-base) var(--ease-out),
                box-shadow var(--duration-base) var(--ease-out),
                border-color var(--duration-base) var(--ease-out);
}
.s-member:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--border-default);
    text-decoration: none;
    color: inherit;
}
/* A PORTRAIT box, because the content is portraits. This was 4/3 — a landscape
   frame — and cover-cropping an upright photo into it threw away most of the
   height: 56% of an ordinary 3:4 phone photo survived, and only 38% of the
   narrowest in the record. Centred, that window opened below the eyes, which is
   why faces arrived cut off from the nose down. At 4/5 the same phone photo
   keeps 94% of itself. */
.s-member__media {
    position: relative;          /* the containing block for the photo below */
    display: grid;
    place-items: center;         /* still centres the initials block */
    aspect-ratio: 4 / 5;
    background: var(--surface-sunken);
    overflow: hidden;
    /* The carousel track is a grid row, so every card is stretched to the
       tallest one — and cards differ because a member with three badges wraps
       onto a second line while one with two does not. Without this the surplus
       collects as dead space under the badges, which on a phone was a third of
       the card. Growing the photograph into it costs nothing: object-fit is
       already filling whatever height it is given. aspect-ratio stays as the
       BASE size, so a row of equal-content cards still looks exactly 4:5. */
    flex-grow: 1;
}
/* Faces are not in the middle of a photograph. In an ordinary head-and-shoulders
   shot the crown sits around 6% down and the eyes around 27%, so whatever has to
   be discarded should come off the bottom, not be split evenly top and bottom.
   28% puts the crop window over the face instead of through it.

   position:absolute + inset:0 rather than width/height:100%, and this is
   load-bearing in two separate ways:

   1. As a grid item the image kept min-height:auto, which floors a replaced
      element at its own content height. A 225x300 photo in a 238px-wide box
      therefore laid out 317px tall inside a 298px box — height:100% simply
      lost. object-fit had nothing left to crop, object-position did nothing at
      all, and the "crop" you saw was overflow:hidden clipping the bottom.
   2. iOS Safari does not treat a height derived from aspect-ratio as definite
      when resolving a child's percentage height, so height:100% collapsed to
      the photo's intrinsic height and left a band of empty box above it.

   An absolutely positioned element is neither a grid item nor dependent on
   percentage resolution, so both problems go away and the focal point finally
   reaches the page. */
.s-member__media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 28%;
}
/* A member with no photograph, tinted by a hue derived from their id (--tint-h,
   set inline; the same function the family tree uses, so one person is one
   colour everywhere). Plain --surface-sunken beside three photographs reads as
   a hole in the row rather than as a person, and in dark mode it is nearly
   black. Mixed into the theme's own tokens rather than given a fixed lightness,
   so it stays quiet in light mode and stays visible in dark. */
.s-member__media[style*="--tint-h"] {
    background: color-mix(in srgb, hsl(var(--tint-h) 55% 50%) 16%, var(--surface-sunken));
}
.s-member__initials {
    font-size: var(--fs-3xl);
    font-weight: var(--fw-semibold);
    color: var(--text-muted);
    letter-spacing: 0.02em;
}
.s-member__media[style*="--tint-h"] .s-member__initials {
    color: color-mix(in srgb, hsl(var(--tint-h) 55% 50%) 55%, var(--text-secondary));
}
.s-member__body { padding: var(--space-4); }
.s-member__name {
    margin: 0;
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
}
.s-member__popular {
    margin: 2px 0 var(--space-3);
    font-size: var(--fs-sm);
    color: var(--text-muted);
}
.s-member__meta { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ============================================================================
   Programme cards
   ----------------------------------------------------------------------------
   Four boxes, one per fund programme. Each carries its own accent through
   --p-accent, set inline from config/programmes.php, so the set reads as a
   family of four rather than four copies of the same card.

   With no photograph the media panel draws a motif in that accent instead of
   borrowing stock imagery. The site this replaces was built from a copied
   template's stock photographs, and standing in a stranger's photo for family
   work is the same mistake in a new coat.
   ============================================================================ */
.s-programmes {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}

.s-programme {
    display: flex;
    flex-direction: column;
    background: var(--surface-raised);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transition: transform var(--duration-base) var(--ease-out),
                box-shadow var(--duration-base) var(--ease-out),
                border-color var(--duration-base) var(--ease-out);
}
a.s-programme:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: color-mix(in srgb, var(--p-accent) 45%, var(--border-default));
    text-decoration: none;
    color: inherit;
}
a.s-programme:focus-visible { outline: none; box-shadow: var(--ring-focus); }

.s-programme__media {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: color-mix(in srgb, var(--p-accent) 12%, var(--surface-sunken));
    color: var(--p-accent);
}
/* Absolutely positioned for the same two reasons as .s-member__media img above:
   min-height:auto on a grid item, and iOS Safari not resolving a percentage
   height against an aspect-ratio box. Not faces here, but the same collapse. */
.s-programme__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Concentric arcs echoing the hero's lineage motif, tinted per programme. */
.s-programme__motif {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 50% 120%, transparent 0 58px,
            color-mix(in srgb, var(--p-accent) 22%, transparent) 58px 59px, transparent 59px),
        radial-gradient(circle at 50% 120%, transparent 0 96px,
            color-mix(in srgb, var(--p-accent) 16%, transparent) 96px 97px, transparent 97px),
        radial-gradient(circle at 50% 120%, transparent 0 140px,
            color-mix(in srgb, var(--p-accent) 11%, transparent) 140px 141px, transparent 141px);
}
.s-programme__icon { position: relative; width: 34px; height: 34px; }

.s-programme__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    flex: 1;
}
.s-programme__name {
    font-size: var(--fs-base);
    font-weight: var(--fw-semibold);
}
.s-programme__tagline {
    font-size: var(--fs-xs);
    font-weight: var(--fw-medium);
    color: var(--p-accent);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
}
.s-programme__summary {
    margin-top: var(--space-2);
    font-size: var(--fs-sm);
    color: var(--text-secondary);
}
.s-programme__foot { margin-top: auto; padding-top: var(--space-4); }

/* ============================================================================
   Member profile
   ============================================================================ */
.s-profile-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
    align-items: center;
    padding-block: var(--space-10);
}
.s-profile-head__body { flex: 1; min-width: 260px; }
.s-profile-head__name {
    margin: 0 0 var(--space-1);
    font-size: var(--fs-2xl);
    font-weight: var(--fw-semibold);
    letter-spacing: var(--tracking-tight);
}
.s-profile-head__popular { margin: 0 0 var(--space-4); color: var(--text-muted); font-size: var(--fs-md); }
.s-profile-head__badges { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.s-grid {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: 1fr;
}
@media (min-width: 900px) {
    .s-grid--sidebar { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
    .s-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.s-people {
    display: grid;
    gap: var(--space-3);
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.s-person {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    text-decoration: none;
    color: inherit;
    min-width: 0;
}
.s-person:hover { border-color: var(--border-default); background: var(--surface-hover); text-decoration: none; color: inherit; }
.s-person__name {
    display: block;
    font-weight: var(--fw-medium);
    font-size: var(--fs-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.s-person__meta { display: block; font-size: var(--fs-xs); color: var(--text-muted); }

/* Notice explaining that signing in reveals more. */
.s-redacted {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px dashed var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    color: var(--text-muted);
    font-size: var(--fs-sm);
}

/* ============================================================================
   Prose — the About page
   ============================================================================ */
.s-prose { max-width: 68ch; }
.s-prose h2 { margin-top: var(--space-10); font-size: var(--fs-lg); }
.s-prose h3 { margin-top: var(--space-8); font-size: var(--fs-md); }
.s-prose p  { color: var(--text-secondary); }

/* Placeholder blocks awaiting real family copy. Deliberately conspicuous: this
   marks text nobody has written yet, and it must not be mistaken for content. */
.s-todo {
    border-left: 3px solid var(--highlight);
    background: var(--highlight-subtle);
    padding: var(--space-4) var(--space-5);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    margin-block: var(--space-4);
}
.s-todo__label {
    display: inline-block;
    margin-bottom: var(--space-2);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--highlight-text);
}
.s-todo p { margin: 0; color: var(--text-secondary); font-size: var(--fs-sm); }

/* ============================================================================
   Timeline — the About page's lineage outline
   ============================================================================ */
.s-timeline { list-style: none; margin: 0; padding: 0; }
.s-timeline__item {
    position: relative;
    padding: 0 0 var(--space-6) var(--space-8);
    border-left: 1px solid var(--border-default);
}
.s-timeline__item:last-child { border-left-color: transparent; padding-bottom: 0; }
.s-timeline__item::before {
    content: "";
    position: absolute;
    left: -5px;
    top: 4px;
    width: 9px; height: 9px;
    border-radius: var(--radius-full);
    background: var(--accent);
}
.s-timeline__title { margin: 0 0 var(--space-1); font-size: var(--fs-base); font-weight: var(--fw-semibold); }
.s-timeline__meta  { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

/* ============================================================================
   Tree page — full-bleed canvas
   ----------------------------------------------------------------------------
   #tree previously had NO css rule anywhere in the project, which is why the
   canvas had no height.
   ============================================================================ */
/* dvh, not vh: on phones the browser's own chrome slides away as you scroll,
   and 100vh measures the TALLEST state, so a vh-sized canvas is cut off by the
   address bar for as long as it is showing. */
/* The tree is a canvas, not an article: it fills whatever is left below the
   header and the document does not scroll. Previously the page scrolled to
   reveal the footer, and since the toolbar is positioned inside this element,
   scrolling carried the toolbar off the top of the screen.
   The footer is dropped here — every link in it is already in the header.

   Laid out with flex rather than a fixed top offset. The header is one row on
   a desktop and wraps to two on a phone, so any hardcoded offset is wrong on
   one of them: at 402px wide a 57px offset put the toolbar underneath the
   wrapped navigation. */
.s-page--tree { overflow: hidden; }
.s-page--tree body { overflow: hidden; }

body.s-page--tree {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
}
.s-page--tree .s-header { flex: none; }
.s-page--tree main      { flex: 1; min-height: 0; position: relative; }
.s-page--tree .s-footer { display: none; }

.s-tree-page {
    position: absolute;
    inset: 0;
    overflow: hidden;
    /* The canvas handles its own gestures; without this the page itself
       rubber-bands on iOS while you are trying to pan the tree. */
    overscroll-behavior: none;
}
#tree-container, #tree { width: 100%; height: 100%; }

/* ============================================================================
   Footer
   ============================================================================ */
.s-footer {
    border-top: 1px solid var(--border-subtle);
    background: var(--surface-sunken);
}
.s-footer__inner {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-8);
    justify-content: space-between;
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-10) var(--space-6) var(--space-6);
}
.s-footer__note { margin: var(--space-2) 0 0; color: var(--text-muted); font-size: var(--fs-sm); max-width: 40ch; }
.s-footer__nav { display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: flex-start; }
.s-footer__nav a { color: var(--text-secondary); font-size: var(--fs-sm); text-decoration: none; }
.s-footer__nav a:hover { color: var(--accent-text); text-decoration: underline; }
.s-footer__legal {
    max-width: var(--content-max);
    margin: 0 auto;
    padding: var(--space-4) var(--space-6) var(--space-8);
    color: var(--text-muted);
    font-size: var(--fs-xs);
}

/* ============================================================================
   Tree page chrome
   ============================================================================ */
.t-bar {
    position: absolute;
    top: var(--space-3);
    left: var(--space-3);
    right: var(--space-3);
    z-index: var(--z-sticky);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--surface-raised) 92%, transparent);
    backdrop-filter: saturate(1.4) blur(10px);
    box-shadow: var(--shadow-sm);
}
.t-bar__group { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.t-bar__group--search { flex: 1; justify-content: center; }

.t-breadcrumb { min-width: 0; overflow: hidden; }
.t-breadcrumb .c-breadcrumb { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.t-breadcrumb .c-breadcrumb::-webkit-scrollbar { display: none; }
.t-breadcrumb li { white-space: nowrap; }

.t-search { width: min(340px, 100%); position: relative; }
.t-search .c-input { height: 34px; }
.t-search__results {
    position: absolute;
    top: calc(100% + var(--space-2));
    left: 0; right: 0;
    z-index: var(--z-dropdown);
}

/* Loading and error overlays, centred on the canvas. */
.t-state {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    text-align: center;
    color: var(--text-muted);
    pointer-events: none;
}
.t-state[hidden] { display: none; }
.t-state button { pointer-events: auto; }

/* The drawer sits over the canvas rather than beside it, so the tree never
   loses half the screen. */
.t-drawer { z-index: var(--z-drawer); }

@media (max-width: 900px) {
    .t-bar { flex-wrap: wrap; }
    .t-bar__group--search { order: -1; width: 100%; }
}

/* ============================================================================
   Tree on touch devices
   ----------------------------------------------------------------------------
   This tree is read mostly on phones and laptop trackpads, so the controls are
   sized for fingers rather than a cursor.
   ============================================================================ */
@media (pointer: coarse) {
    /* 44px is the smallest reliably tappable target; the 34px desktop icon
       buttons are a miss as often as a hit with a thumb. */
    .t-bar .s-icon-btn { width: 44px; height: 44px; }
    .t-bar .c-btn { height: 40px; }
    .t-search .c-input { height: 40px; font-size: 16px; }  /* 16px stops iOS zooming the page on focus */
}

@media (max-width: 640px) {
    .t-bar {
        top: var(--space-2);
        left: var(--space-2);
        right: var(--space-2);
        gap: var(--space-2);
        padding: var(--space-2);
    }
    /* The ancestry breadcrumb is the first thing to go: it can run to five
       names and would push the controls off a phone screen. The drawer still
       shows the full lineage. */
    .t-breadcrumb { display: none; }

    .t-bar__group--search { order: -1; }
    .t-search { width: 100%; }

    /* Zoom buttons are redundant once pinch works, and "Back to the founder"
       is a long label on a narrow bar. */
    .t-bar [data-tree-zoom] { display: none; }
    .t-bar .c-btn { font-size: var(--fs-xs); padding: 0 var(--space-3); }
}

/* A one-off hint, shown until the reader touches the canvas. Fingers do not
   advertise their own gestures the way a cursor and a scrollbar do. */
.t-hint {
    position: absolute;
    left: 50%;
    bottom: var(--space-6);
    transform: translateX(-50%);
    z-index: var(--z-sticky);
    display: none;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-full);
    background: color-mix(in srgb, var(--surface-inverse) 88%, transparent);
    color: var(--text-inverse);
    font-size: var(--fs-xs);
    white-space: nowrap;
    pointer-events: none;
    animation: t-hint-fade 400ms var(--ease-out);
}
@media (pointer: coarse) { .t-hint { display: flex; } }
.t-hint[hidden] { display: none; }
@keyframes t-hint-fade { from { opacity: 0; transform: translate(-50%, 8px); } }
