/* André Ferreira — site styles
   Palette: all-black ground, light cream type, light-wood accent.
   Fonts: Cormorant Garamond (display) + Nunito (body).
*/

:root{
  --black:#0a0a0a; --bg:#0a0a0a; --ink:#f1ece1; --sub:#a89c86; --line:rgba(241,236,225,.16); --wood:#d9b98a;
  /* --font-display is the hero name only; everything else that used to be
     Cormorant is now the geometric sans. */
  --font-display:'Cormorant Garamond',Georgia,serif;
  --font-heading:'Montserrat',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --font-body:'Nunito',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  /* Lateral gutters: one eighth of the viewport each side, so content sits in
     the middle six columns of a notional 8. Floored so phones keep a usable
     margin rather than 12.5% of 375px. */
  --pad:max(22px,12.5vw);
}

*{ box-sizing:border-box; }
/* In-page jumps would otherwise land with the heading tucked under the sticky
   bar, which is 69px tall. */
[id]{ scroll-margin-top:88px; }
html{ scroll-behavior:smooth; }
@media(prefers-reduced-motion:reduce){ html{ scroll-behavior:auto; } }
html,body{ margin:0; padding:0; }
body{ background:var(--bg); color:var(--ink); font-family:var(--font-body); }
a{ color:inherit; }
img{ max-width:100%; display:block; }

/* top bar */
/* Sticky rather than fixed: it stays in normal flow, so the hero still
   starts below it instead of sliding under and losing the top of the photo.
   The hairline matters — bar and page background are the same black, so
   without it content appears to dissolve into the bar as you scroll. */
.topbar{ background:var(--black); color:#f2ede2; display:flex; align-items:center; justify-content:space-between;
  padding:16px var(--pad); gap:clamp(14px,2vw,32px); position:sticky; top:0; z-index:10; border-bottom:1px solid var(--line); }
/* Logo and name are one link home. The name is the link's accessible text,
   so the image beside it is decorative (alt=""). */
.brand{ display:flex; align-items:center; gap:11px; flex:0 0 auto; text-decoration:none; color:inherit; }
.brand-name{ font-family:var(--font-heading); font-weight:400; font-size:.9rem;
  text-transform:uppercase; letter-spacing:.07em; white-space:nowrap; }
/* The circle is CSS, not a pre-masked file — the source stays a plain square. */
.mono{ width:36px; height:36px; border-radius:50%; overflow:hidden; display:block;
  flex:0 0 auto; text-decoration:none; background:#131010; }
.mono img{ width:100%; height:100%; object-fit:cover; display:block; }
.burger{ appearance:none; background:none; border:0; cursor:pointer; padding:6px; display:flex; flex-direction:column; gap:5px; }
.burger span{ width:24px; height:2px; background:#f2ede2; display:block; }
.menu{ position:absolute; top:100%; right:var(--pad); background:var(--black); color:#f2ede2; padding:18px 22px; display:none; flex-direction:column; gap:12px; min-width:200px; border:1px solid rgba(242,237,226,.15); z-index:5; }
.menu.open{ display:flex; }
.menu a{ text-decoration:none; color:inherit; font-size:.86rem; letter-spacing:.05em; text-transform:uppercase; opacity:.88; }
.menu a:hover{ opacity:1; }
.menu a[aria-current="page"]{ opacity:1; color:var(--wood); }
.menu .langs{ display:flex; gap:8px; padding-top:8px; border-top:1px solid rgba(242,237,226,.15); }
.menu .langs button{ appearance:none; background:none; border:1px solid rgba(242,237,226,.4); color:#f2ede2; font-size:.72rem; letter-spacing:.05em; padding:4px 9px; cursor:pointer; }
.menu .langs button[aria-pressed="true"]{ background:var(--wood); border-color:var(--wood); color:#141005; }

/* Narrow first: the menu is a dropdown behind the burger. From 768px up — iPad
   portrait included — there is room for all six items plus the language buttons
   on one line, so the whole thing flattens into the bar and the burger goes.
   Width, not user agent: iPadOS Safari reports itself as macOS, so sniffing
   would miss the very device this targets. */
@media(min-width:768px){
  .burger{ display:none; }
  .menu{ position:static; display:flex; flex-direction:row; align-items:center;
    gap:clamp(14px,2vw,30px); background:none; border:0; padding:0; min-width:0; }
  .menu .langs{ padding:0 0 0 clamp(14px,1.8vw,22px); margin-left:2px;
    border-top:0; border-left:1px solid rgba(242,237,226,.15); }
}
/* Comfortable tap targets while it is still a dropdown. */
@media(max-width:767px){
  .menu{ gap:2px; padding:10px 22px 18px; }
  .menu a{ padding:9px 0; }
}

/* hero */
/* The hero box carries the photo's own 3:2 ratio and nothing else constrains
   its height, so the image always scales to the page width and `cover` has
   nothing to crop — no min-height, which would make the box taller than 3:2 on
   narrower windows and clip the sides instead. */
.hero{ position:relative; aspect-ratio:3/2; background:
    linear-gradient(180deg, rgba(6,5,4,.05) 0%, rgba(6,5,4,.75) 78%, rgba(6,5,4,.92) 100%),
    /* Top-anchored so the head is never cut in the cropped (narrow) case. */
    url('../img/hero.jpg') 50% 0% / cover no-repeat,
    radial-gradient(circle at 32% 30%, #6b5d4f 0%, #453a30 42%, #221c16 100%);
  display:block; }
/* The hero is now taller than the screen on most displays, so the name is
   pinned to the bottom of the FIRST screenful rather than the bottom of the
   photo — otherwise it would open below the fold. Falls back to the hero's own
   bottom when the photo is the shorter of the two. */
/* Phones: a 3:2 landscape frame is only about 260px tall at 390px wide, which
   wastes the screen and pulls the next section up into view. Drop the ratio and
   give it most of the viewport instead — `cover` then scales the photo by
   height and trims the sides, so it reads as a portrait crop and nothing is
   lost off the top. svh rather than vh so mobile browser chrome doesn't make
   the hero taller than the visible area. */
@media(max-width:767px){
  .hero{ aspect-ratio:auto; min-height:82vh; min-height:82svh; }
}

.hero-inner{ position:absolute; left:0; right:0; top:0; height:min(88vh,100%);
  display:flex; flex-direction:column; justify-content:flex-end; align-items:flex-start;
  padding:0 var(--pad) clamp(30px,6vw,56px); color:#f7f3ea; }
.hero .eyebrow{ font-size:1.1rem; letter-spacing:.16em; text-transform:uppercase; margin:0 0 18px; color:#d9cdb2; font-weight:600; }
/* 7vw rather than 9vw: the cap is then reached at ~1417px instead of ~1102px,
   so the name starts scaling down as soon as the window leaves a full
   desktop width rather than holding its maximum well into laptop sizes. */
.hero h1{ font-family:var(--font-display); font-weight:400; font-size:clamp(3rem,9vw,6.2rem); line-height:.94; letter-spacing:.02em; text-transform:uppercase; margin:0 0 20px; text-wrap:balance; }
.hero .cta{ display:inline-flex; align-items:center; gap:8px; text-decoration:none; font-size:0.9rem; letter-spacing:.03em; padding-bottom:4px; }

/* bio */
/* photo beside a block of text — about / guitar / lute / contact.
   The four page photos are all 2:3 portrait. */
.split{ padding:clamp(40px,7vw,80px) var(--pad); display:grid; grid-template-columns:0.72fr 1fr;
  gap:clamp(28px,5vw,64px); align-items:center; }
.split-photo{ aspect-ratio:2/3; overflow:hidden; background:#131010; }
.split-photo img{ width:100%; height:100%; object-fit:cover; }
/* Guitar mirrors the split — words left, photo right — so two pages in a row
   don't open with the same picture-then-text rhythm. The mirroring is done
   with grid placement rather than by reordering the markup, so the photo
   stays first in the source: stacked on a phone it still leads, as it does on
   every other page. The column ratio flips with it, keeping the text on the
   wider side. */
.split.reverse{ grid-template-columns:1fr 0.72fr; }
.split.reverse .split-photo{ grid-column:2; grid-row:1; }
.split.reverse .split-body{ grid-column:1; grid-row:1; }
/* No max-width: the column itself is the measure, and the page's 1/8 gutter
   is the only thing holding the text off the right edge. */
.bio-body p{ font-size:1.12rem; line-height:1.75; color:var(--ink); margin:0 0 26px; }
.bio-body p:last-child{ margin-bottom:0; }
@media(max-width:767px){
  .split, .split.reverse{ grid-template-columns:1fr; }
  .split.reverse .split-photo, .split.reverse .split-body{ grid-column:auto; grid-row:auto; }
  .split-photo{ max-width:340px; }
}
/* Tablet: keep the two columns, but the text column runs tall at this width,
   which left the photo looking small and stranded mid-paragraph. Widen its
   share and align both to the top so they start on the same line. */
@media(min-width:768px) and (max-width:1023px){
  .split, .intro{ grid-template-columns:0.95fr 1fr; align-items:start; }
  .split.reverse{ grid-template-columns:1fr 0.95fr; }
  /* Wider gutters mean less room for the bar; tighten it instead of dropping
     back to a burger at a width where the full nav still reads fine. */
  .menu{ gap:clamp(10px,1.4vw,18px); }
  .menu a{ font-size:.78rem; letter-spacing:.03em; }
  .menu .langs{ padding-left:12px; }
  .menu .langs button{ font-size:.66rem; padding:3px 7px; }
  .brand{ gap:9px; }
  .brand-name{ font-size:.8rem; letter-spacing:.05em; }
}

/* concerts */
.concerts-wrap{ padding:0 var(--pad) clamp(48px,8vw,88px); }
.concerts-wrap h2{ font-family:var(--font-heading); font-weight:600; font-size:clamp(1.5rem,2.6vw,2rem); letter-spacing:.01em; margin:0 0 30px; }
.concerts-wrap .note{ font-size:.82rem; color:var(--sub); margin:0 0 30px; }
.clist{ border-top:1px solid var(--line); }
/* Year markers in the archive. */
.cyear{ font-family:var(--font-heading); font-weight:700; font-size:1.35rem; letter-spacing:.06em;
  color:var(--ink); margin:0; padding:clamp(56px,7.5vw,112px) 0 14px; border-bottom:1px solid var(--line); }
.cyear:first-child{ padding-top:16px; }
.crow{ display:grid; grid-template-columns:minmax(190px,0.62fr) 1fr auto; align-items:center; gap:16px; padding:22px 0; border-bottom:1px solid var(--line); }
.crow .date{ display:block; font-weight:800; font-size:.95rem; letter-spacing:.02em; font-variant-numeric:tabular-nums; white-space:nowrap; }
.crow .title{ font-size:1.02rem; }
.crow .tname{ display:block; font-family:var(--font-heading); font-weight:600; letter-spacing:.005em; }
.crow .performers{ display:block; font-size:.86rem; line-height:1.45; color:var(--sub); margin-top:4px; }
.crow .venue{ margin-top:7px; font-size:.88rem; line-height:1.45; color:var(--sub); }
/* Upcoming lists — the home page's next dates and the archive page's top
   section — lift the venue to the brighter wood; the past archive keeps it
   muted. */
.concerts-wrap:not(.past) .crow .venue{ color:var(--wood); }
.crow .tix{ text-decoration:none; font-size:.82rem; letter-spacing:.05em; text-transform:uppercase; white-space:nowrap; border-bottom:1px solid var(--ink); padding-bottom:3px; }
@media(max-width:760px){ .crow{ grid-template-columns:1fr; gap:4px; padding:18px 0; } .crow .tix{ justify-self:start; margin-top:6px; } }

/* video / teaching */
.band{ padding:clamp(44px,7vw,72px) var(--pad); border-top:1px solid var(--line); }
.band h2{ font-family:var(--font-heading); font-weight:600; font-size:1.5rem; letter-spacing:.01em; margin:0 0 22px; }
.band .note{ font-size:.82rem; color:var(--sub); margin:-14px 0 24px; }
.video-card{ max-width:720px; margin-inline:auto; }
.video-thumb{ appearance:none; padding:0; width:100%; display:block; cursor:pointer; color:inherit; font:inherit;
position:relative; aspect-ratio:16/9; overflow:hidden; border:0; background:
radial-gradient(circle at 68% 32%, #3a322a 0%, #1c1712 62%, #100d0a 100%); }
.video-thumb img{ width:100%; height:100%; object-fit:cover; }
.video-thumb .play{ position:absolute; inset:0; margin:auto; width:64px; height:64px; border-radius:50%; background:rgba(243,239,230,.92); display:flex; align-items:center; justify-content:center; transition:background .15s; }
.video-thumb .play svg{ width:20px; height:20px; fill:#141005; margin-left:3px; }
.video-thumb:focus-visible .play{ background:var(--wood); }
/* Only where a pointer can actually hover. On a touch screen Safari may spend
   the first tap turning the hover state on rather than firing the click, so a
   hover rule on the play button costs an iPhone a tap. */
@media(hover:hover){ .video-thumb:hover .play{ background:var(--wood); } }
/* replaces .video-thumb once play is pressed */
.video-player{ position:relative; aspect-ratio:16/9; overflow:hidden; background:#000; }
.video-player iframe{ position:absolute; inset:0; width:100%; height:100%; border:0; }
.video-caption{ display:flex; justify-content:space-between; align-items:baseline; gap:12px; padding-top:14px; flex-wrap:wrap; }
.video-caption .vt{ font-size:1.02rem; }
.video-caption .vl{ text-decoration:none; font-size:.82rem; letter-spacing:.05em; text-transform:uppercase; border-bottom:1px solid var(--ink); padding-bottom:3px; white-space:nowrap; }
.prose{ max-width:60ch; font-size:1.05rem; line-height:1.7; }
.split .prose{ max-width:none; }

/* Headings written in the Markdown (## in content/) land inside a text block
   with no class to hang a rule on. The site's heading face, sized to sit
   under the page's own <h1> rather than compete with it; ### drops to the
   small wood eyebrow the section labels use elsewhere. */
.bio-body h2, .prose h2, .intro-text h2{
  font-family:var(--font-heading); font-weight:600; font-size:1.3rem;
  letter-spacing:.01em; line-height:1.3; color:var(--wood); margin:38px 0 14px;
}
.bio-body h3, .prose h3, .intro-text h3,
.bio-body h4, .prose h4, .intro-text h4{
  font-family:var(--font-heading); font-weight:600; font-size:.88rem;
  letter-spacing:.08em; text-transform:uppercase; color:var(--wood);
  margin:32px 0 10px;
}
/* A text that opens on a heading shouldn't push itself down the column. */
.bio-body > :first-child, .prose > :first-child, .intro-text > :first-child{ margin-top:0; }

/* page header — every page but home opens with one */
.page-head{ padding:clamp(40px,7vw,72px) var(--pad) clamp(18px,3vw,28px); }
.page-head h1{ font-family:var(--font-heading); font-weight:600; font-size:clamp(1.9rem,4vw,2.9rem);
  line-height:1; letter-spacing:.02em; text-transform:uppercase; margin:0; }

/* home: photo left, introduction and the three section links right.
   Sits on the page background — no cards, no lighter panels. */
.intro{ padding:clamp(44px,7vw,72px) var(--pad); border-top:1px solid var(--line);
  display:grid; grid-template-columns:0.72fr 1fr; gap:clamp(28px,5vw,64px); align-items:center; }
.intro-photo{ aspect-ratio:1/1; overflow:hidden; background:#131010; }
.intro-photo img{ width:100%; height:100%; object-fit:cover; }
.intro-text{ margin:0 0 clamp(22px,3vw,32px); font-size:1.12rem; line-height:1.75; color:var(--ink); max-width:52ch; }
.intro-text p{ margin:0 0 16px; }
.intro-text p:last-child{ margin-bottom:0; }
.intro-links{ display:flex; flex-direction:column; border-top:1px solid var(--line); }
.ilink{ display:block; text-decoration:none; color:inherit; padding:17px 0;
  border-bottom:1px solid var(--line); }
.ilabel{ display:inline-block; font-size:.78rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--wood); margin-bottom:7px; }
.ilabel::after{ content:' →'; }
.idesc{ display:block; font-size:.95rem; line-height:1.6; color:var(--ink); max-width:48ch; }
@media(max-width:767px){
  .intro{ grid-template-columns:1fr; }
  .intro-photo{ max-width:340px; }
}

/* a cta used as a standalone block rather than inside the hero */
/* .cta outside the hero had no rule at all, so this link fell back to browser
   defaults. Match the ticket links instead; .hero .cta still overrides it. */
.cta{ display:inline-flex; align-items:center; gap:8px; text-decoration:none;
  font-size:.82rem; letter-spacing:.06em; text-transform:uppercase;
  border-bottom:1px solid var(--wood); padding-bottom:4px; }
.cta:hover, .cta:focus-visible{ color:var(--wood); }
/* Pushed right so it lines up with the ticket links above it. display:flex
   (not the inline-flex it inherits from .cta) makes it block-level, which
   is what lets the auto left margin do the pushing; fit-content keeps the
   underline hugging the text rather than spanning the row. */
.cta-block{ display:flex; width:fit-content; margin:34px 0 0 auto; }
.prose + .cta{ margin-top:26px; }

/* dates page: the archive reads quieter than the upcoming list */
.concerts-wrap.past{ border-top:1px solid var(--line); padding-top:clamp(44px,7vw,72px); }
/* The archive never renders ticket links (build.py passes tickets=False), so
   it drops that third track and splits the full width evenly instead. */
/* No rule under the heading — the first year heading below it already carries
   one, and two lines 30px apart read as a mistake. */
.concerts-wrap.past .clist{ border-top:0; }
.concerts-wrap.past .crow{ padding:15px 0; grid-template-columns:1fr 1fr; }
.concerts-wrap.past .crow .date, .concerts-wrap.past .crow .tname{ color:var(--sub); }
.concerts-wrap.past .crow .performers{ font-size:.82rem; }

/* prose blocks are now containers holding paragraphs, not paragraphs */
.prose p{ margin:0 0 20px; }
.prose p:last-child{ margin-bottom:0; }

/* contact */
.contact-list{ list-style:none; margin:28px 0 0; padding:0; border-top:1px solid var(--line); max-width:560px; }
.contact-list li{ display:flex; flex-wrap:wrap; gap:6px 24px; align-items:baseline;
  padding:16px 0; border-bottom:1px solid var(--line); }
.contact-list .clabel{ flex:0 0 96px; font-size:.72rem; letter-spacing:.08em; text-transform:uppercase; color:var(--sub); }
.contact-list a{ text-decoration:none; border-bottom:1px solid var(--wood); padding-bottom:2px; }

/* contact: the press kit, under the email and sharing its column width. The
   link and the line under it are generated with the file itself
   (scripts/press_kit.py), so the size and photo count can't drift from what is
   actually in the zip — and a build that produced no kit leaves the block with
   nothing to click rather than a dead link. */
.presskit{ max-width:560px; margin-top:clamp(28px,4vw,40px); }
.presskit h2{ font-family:var(--font-heading); font-weight:600; font-size:1.15rem;
  letter-spacing:.01em; margin:0 0 9px; }
/* Set below the intro prose above it: this is a secondary offer, not a second
   paragraph of the same weight. */
.presskit .pk-desc{ font-size:.95rem; line-height:1.6; color:var(--ink); margin:0; max-width:48ch; }
.presskit .cta{ margin-top:20px; }
.presskit .pk-meta{ font-size:.78rem; letter-spacing:.04em; color:var(--sub); margin:12px 0 0; }
/* Credit for the press-kit photographs, under the whole block. */
.photo-credit{ max-width:560px; font-size:.78rem; letter-spacing:.04em; color:var(--sub);
  margin:clamp(20px,3vw,28px) 0 0; padding-top:14px; border-top:1px solid var(--line); }

.foot{ background:var(--black); color:#e9e3d5; padding:26px var(--pad); display:flex; flex-wrap:wrap; gap:12px; justify-content:center; align-items:center; font-size:.82rem; }
.social{ list-style:none; display:flex; align-items:center; gap:32px; margin:0; padding:0; }
.social a{ display:block; color:#e9e3d5; opacity:.75; }
.social a:hover, .social a:focus-visible{ opacity:1; color:var(--wood); }
.social svg{ width:24px; height:24px; fill:currentColor; display:block; }

/* ---------- links -------------------------------------------------------
   One treatment for every text link: underlined in its own colour. The two
   directions are colour-swapped so you can tell at a glance whether a link
   keeps you on the site or takes you off it.
     stays here  -> wood, turns white on hover
     leaves here -> white, turns wood on hover
   "Leaves" is detected by target="_blank" and mailto:, both of which the
   markup already carries, so no extra classes are needed. */
.cta, .crow .tix, .video-caption .vl, .ilabel, .contact-list a{
  text-decoration:none;
  border-bottom:1px solid currentColor;
  color:var(--wood);
}
.cta:hover, .cta:focus-visible,
.crow .tix:hover, .crow .tix:focus-visible,
.video-caption .vl:hover, .video-caption .vl:focus-visible,
.ilink:hover .ilabel, .ilink:focus-visible .ilabel,
.contact-list a:hover, .contact-list a:focus-visible{ color:var(--ink); }

/* The class selectors above outrank a bare a[target], so the outbound rules
   repeat those classes to win the cascade rather than relying on order. */
a[target="_blank"], a[href^="mailto:"],
.cta[target="_blank"], .crow .tix[target="_blank"],
.video-caption .vl[target="_blank"],
.contact-list a[target="_blank"], .contact-list a[href^="mailto:"]{ color:var(--ink); }

a[target="_blank"]:hover, a[target="_blank"]:focus-visible,
a[href^="mailto:"]:hover, a[href^="mailto:"]:focus-visible,
.cta[target="_blank"]:hover, .cta[target="_blank"]:focus-visible,
.crow .tix[target="_blank"]:hover, .crow .tix[target="_blank"]:focus-visible,
.video-caption .vl[target="_blank"]:hover, .video-caption .vl[target="_blank"]:focus-visible,
.contact-list a[target="_blank"]:hover, .contact-list a[target="_blank"]:focus-visible,
.contact-list a[href^="mailto:"]:hover, .contact-list a[href^="mailto:"]:focus-visible{ color:var(--wood); }
/* Links inside the running text come from the Markdown — [label](url) in
   content/ — so they carry no class to hang a rule on. Same underline as
   every other text link; the colour rules above already tell a link that
   leaves the site from one that doesn't. */
.bio-body a, .prose a, .intro-text a{
  text-decoration:none;
  border-bottom:1px solid currentColor;
}

/* the footer icons keep their own scheme — no underline on a glyph */
.social a{ border-bottom:0; }
