@charset "UTF-8";

/* ==================================================================
   Duke Kahanamoku Gallery

   Palette, type and spacing follow DUKE-BRAND-CORE.md section 5.
   Two rules shaped this file more than any taste of mine:

   1. No photograph of DUKE may appear until it is cleared in writing,
      per image, so the design can never lean on a portrait of him. It
      leans on photographs of the ROOM instead, which arrived in
      September. Until they did this was a type-only page, and the
      Composition section further down explains what changed.

   2. The restraint rule: two brand colours plus one neutral on any one
      surface. Gold is used five times and only five: the hero waterline,
      the list bullet, the pull-quote rule, the footer tagline, and the
      primary button on hover. Four of those are non-text marks. The one
      that is text, the tagline, is set at 24px, because gold on Duke Blue
      is 3.8:1 and clears the 3:1 large-text bar and nothing below it.

   Colour values are marked PROVISIONAL in the canon pending Kenneth
   Berger's confirmation of the blue. They are variables for that reason.
   ================================================================== */

:root {
  /* brand */
  --duke-blue: #003b5c;
  --olympic-gold: #b08d57;
  --waikiki-sand: #dfd3c3;
  --surf-white: #edece6;
  --koa-brown: #4d3930;

  /* derived. tints are for backgrounds and UI only, never the logo */
  --blue-80: #336277;
  --blue-60: #668992;
  --rule: rgba(0, 59, 92, 0.22);
  --rule-link: rgba(0, 59, 92, 0.55);   /* 3.1:1 on Surf White, for 1.4.1 */
  --rule-soft: rgba(0, 59, 92, 0.12);

  /* surfaces */
  --bg: var(--surf-white);
  --ink: var(--duke-blue);
  --ink-quiet: #3d5a6b;

  /* type */
  --serif: "EB Garamond", "EBGaramond", Garamond, "Times New Roman", Times, serif;
  --sans: Arial, "Helvetica Neue", Helvetica, sans-serif;
  /* EB Garamond has no Japanese glyphs and Arial's coverage depends on the
     platform. The /ja/ page hands off to whatever the reader's system has,
     which is what a Japanese reader expects anyway. */
  --ja: "Hiragino Kaku Gothic ProN", "Hiragino Sans", "Yu Gothic Medium",
        "Noto Sans JP", "Meiryo", sans-serif;

  /* measure and rhythm */
  /* 30rem is 480px, which measures 62 characters in Arial 16. 34rem measured
     71, which is too many for a face whose x-height is 28% larger than the
     serif it sits under. */
  --measure: 30rem;
  --wrap: 68rem;

  --pad-x: clamp(1.25rem, 5vw, 3rem);
  --sect-y: clamp(3.75rem, 9vw, 7rem);
  /* A hero is not a body section. It was getting the same 112px standoff as
     the gap between two paragraphs of history. */
  --hero-y: clamp(4.5rem, 13vw, 10.5rem);
  /* One breakpoint for every two-column collapse. The plates grid broke at
     46rem and the visit blocks at 52rem, so 768px showed 2-up plates beside
     1-up blocks on the same site. */
  --bp-two-col: 48rem;
}

/* ------------------------------------------------------------------
   EB Garamond, self-hosted. Nothing is fetched from Google at runtime,
   which is what lets the CSP in static/_headers stay strict.

   Two subsets per face, and both are needed:
     latin      carries U+02BB, the ʻokina
     latin-ext  carries the kahakō, ā ē ī ō ū

   Drop latin-ext and Waikīkī loses both its marks while the ʻokina in
   Hawaiʻi survives, which is the worst possible failure because it looks
   deliberate.

   Four files. Three actually load on any page: regular-latin, regular-
   latin-ext and medium-latin, about 104KB. medium-latin-ext is here for the
   day a Hawaiian word lands in a 500-weight string, and browsers will not
   fetch it until then. There is no italic: nothing on the site is italic,
   and shipping two faces nobody requests is 70KB of dead weight in every
   deploy. If you add an <em>, add the face back.
   ------------------------------------------------------------------ */

@font-face {
  font-family: "EB Garamond"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/assets/fonts/EBGaramond-regular-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "EB Garamond"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/assets/fonts/EBGaramond-regular-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "EB Garamond"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/assets/fonts/EBGaramond-medium-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "EB Garamond"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/assets/fonts/EBGaramond-medium-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------------
   reset, minimal
   ------------------------------------------------------------------ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  /* Full-bleed sections break out with 100vw. Without this, that breakout
     adds a horizontal scrollbar on every platform that reserves gutter
     space for the vertical one. clip, not hidden, so position:sticky in the
     editorial columns still works. */
  overflow-x: clip;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  /* canon: body never below 16px */
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { margin: 0; font-weight: 400; }
p { margin: 0 0 1.15em; }
ul { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; height: auto; display: block; }

/* Links carry no colour difference from body text, so the underline is the
   only thing distinguishing them and it has to clear 3:1 against the
   background on its own. --rule is 1.49:1 and was not enough. */
a {
  color: inherit;
  text-decoration: none;
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
  border-bottom: 1px solid var(--rule-link);
  transition: border-color 140ms ease, color 140ms ease;
}
a:hover { border-bottom-color: currentColor; }

:focus-visible {
  outline: 2px solid var(--duke-blue);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--duke-blue);
  color: var(--surf-white);
  padding: 0.75rem 1.25rem;
  border: 0;
}
.skip:focus { left: 0; }

/* ------------------------------------------------------------------
   layout
   ------------------------------------------------------------------ */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}
/* Reading sections keep the same left edge as everything else and constrain
   the line length on the inner elements instead. Centring a narrow column
   inside a wide page gives every other section a different left margin, and
   the eye reads that as sloppiness before it reads anything else. */
.wrap--reading { max-width: var(--wrap); }
.wrap--reading > .lede,
.wrap--reading > .closing,
.wrap--reading > .more,
.wrap--reading > p { max-width: var(--measure); }

.main > .section,
.main > .orient { padding-block: var(--sect-y); }
/* Generous above, restrained below. Symmetric hero padding put 280px of
   nothing between the subhead and the first paragraph at 1280, because the
   hero's own bottom padding and the next section's top padding stacked. */
.main > .hero { padding-block: var(--hero-y) calc(var(--sect-y) * 0.4); }

/* .orient carried no .section class, so it got zero padding and
   .section + .section never fired across it. Home's rule system started
   three sections in. */
.orient + .section { border-top: 1px solid var(--rule-soft); }

.section + .section { border-top: 1px solid var(--rule-soft); }

/* ------------------------------------------------------------------
   masthead
   ------------------------------------------------------------------ */

.masthead {
  border-bottom: 1px solid var(--rule-soft);
  background: var(--bg);
}
.masthead__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 1.35rem var(--pad-x);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.lockup {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  border: 0;
}
.lockup__descriptor {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  color: var(--ink-quiet);
  /* the descriptor is the one place we uppercase, and it is an English
     word with no diacriticals in it, which is the only reason it is safe */
  text-transform: uppercase;
}

/* The licensed signature, once it exists. Placed as artwork, once. */
.signature {
  display: block;
  max-width: 15rem;
}

/* The interim wordmark. Duke Blue on Surf White, EB Garamond, letterspaced,
   and deliberately nothing like a signature: no script face, no slant, no
   underline that could read as a hand-drawn rule. It carries no diacriticals,
   which is the only reason it is safe to letterspace at this size. */
.wordmark {
  font-family: var(--serif);
  font-size: 1.35rem;
  line-height: 1;
  letter-spacing: 0.03em;
  color: var(--ink);
}

.nav ul {
  display: flex;
  gap: clamp(1rem, 3vw, 2rem);
  flex-wrap: wrap;
}
/* Measured tap targets were 19px tall. The negative margin on the list keeps
   the visual position while the padding does the work. */
.nav ul { margin-block: -0.65rem; }
.nav a {
  display: inline-block;
  font-size: 1rem;
  letter-spacing: 0.02em;
  border-bottom: 1px solid transparent;
  padding-block: 0.65rem;
}
.nav a:hover,
.nav a[aria-current="page"] { border-bottom-color: var(--duke-blue); }
.nav a[aria-current="page"] { color: var(--duke-blue); }

/* ------------------------------------------------------------------
   type
   ------------------------------------------------------------------ */

/* Eyebrows are NOT uppercased in CSS, and this is deliberate. They carry
   Waikīkī and Kalākaua, and text-transform: uppercase is where the ʻokina
   and the kahakō die: the browser transforms the codepoint, the font
   substitutes what it has, and nobody sees it until it is on a live page.
   Small size plus wide tracking gives the same label reading without ever
   putting a Hawaiian word through a transform. The only uppercased strings
   on this site are GALLERY and ALOHA TO YOU, both English, both mark-free,
   and both checked by scripts/brand-check.mjs. */
.eyebrow {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--ink-quiet);
  margin: 0 0 0.9rem;
}

.hero__headline {
  font-family: var(--serif);
  /* The floor was 2.1rem, and the vw term did not engage until 542px, so
     every phone got 33.6px. Against Arial 16, whose x-height makes it read
     like 20.5px, that is a display-to-body ratio of 1.6 on the screen where
     the site is most likely to be read. */
  font-size: clamp(2.5rem, 8.5vw, 3.9rem);
  line-height: 1.12;
  letter-spacing: -0.005em;
  max-width: 18ch;
  /* NOT uppercased. The canon's sample stack sets titles in caps, but
     uppercase is where the ʻokina and kahakō die, and this page carries
     Kalākaua, Waikīkī and Hawaiʻi in headings. Sentence case is the
     safer reading of a rule whose purpose is to protect the marks. */
}
@media (min-width: 46rem) { .hero__headline { line-height: 1.08; } }
.hero--wide .hero__headline { max-width: 15ch; }

.hero__sub {
  font-family: var(--serif);
  font-size: clamp(1.15rem, 2.4vw, 1.4rem);
  line-height: 1.5;
  max-width: 44ch;
  margin-top: 1.5rem;
  color: var(--ink-quiet);
}

.section__head {
  font-family: var(--serif);
  font-size: clamp(1.65rem, 3.6vw, 2.4rem);
  line-height: 1.15;
  max-width: 20ch;
}
.section__head--small { font-size: clamp(1.3rem, 2.6vw, 1.6rem); }

.prose { max-width: var(--measure); }
.prose p { margin-bottom: 1.35em; }
.prose p:last-child { margin-bottom: 0; }

.para--emphasis {
  font-family: var(--serif);
  font-size: 1.35rem;
  line-height: 1.45;
  color: var(--duke-blue);
}

.lede { max-width: var(--measure); }
/* A lede following prose was butting straight onto the last paragraph. */
.prose + .lede,
.prose + .roster { margin-top: 2rem; }

/* .note carries real information, not decoration: parking is unconfirmed,
   the mailbox is closed, the film rights are not cleared. Canon puts the
   floor for body copy at 16px and this is body copy. */
.note {
  font-size: 1rem;
  color: var(--ink-quiet);
  max-width: var(--measure);
  padding-left: 1rem;
  border-left: 2px solid var(--waikiki-sand);
}

/* ------------------------------------------------------------------
   waterline rule, from the brand book: three lines
   ------------------------------------------------------------------ */

/* It was 168px fixed: 17% of the content column at 1280 and 53% at 375, so
   the same mark had three different weights against the type it divides. */
.waterline {
  color: rgba(0, 59, 92, 0.34);
  width: min(168px, 34%);
  height: auto;
  margin: 1.5rem 0;
}
.waterline--hero {
  margin: 2.25rem 0 0;
  width: min(220px, 44%);
  color: var(--olympic-gold);
}
.waterline--footer { margin: 0 auto 1.5rem; }

/* ------------------------------------------------------------------
   home: the three questions
   ------------------------------------------------------------------ */

.orient__grid {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
  grid-template-columns: 1fr;
}
@media (min-width: 52rem) {
  .orient__grid { grid-template-columns: repeat(3, 1fr); }
}
.orient__q {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin-bottom: 0.8rem;
  padding-bottom: 0.8rem;
  border-bottom: 1px solid var(--rule-soft);
}
/* Once the three-column grid collapses at --bp-two-col these run the full
   column: 90 characters at 768px. */
.orient__a { margin: 0; max-width: var(--measure); }

/* ------------------------------------------------------------------
   pull quote, handoff, aside
   ------------------------------------------------------------------ */

.pull {
  margin: 2.5rem 0 0;
  padding-left: 1.5rem;
  border-left: 2px solid var(--olympic-gold);
  max-width: var(--measure);
}
.pull p {
  font-family: var(--serif);
  font-size: clamp(1.25rem, 2.6vw, 1.5rem);
  line-height: 1.45;
  margin: 0;
}

.handoff {
  margin-top: 2.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule-soft);
  max-width: var(--measure);
  font-family: var(--serif);
  font-size: 1.2rem;
  line-height: 1.55;
}

.aside {
  margin-top: 2.5rem;
  padding: 1.75rem;
  background: rgba(223, 211, 195, 0.4);
  max-width: var(--measure);
}
.aside__head {
  font-family: var(--serif);
  font-size: 1.3rem;
  margin-bottom: 0.6rem;
}
.aside p:last-child { margin-bottom: 0; }

/* The makers are the whole proposition and the roster is not built. A maker
   who lands here should have a way in, and this is it. */
.makers__call {
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule-soft);
  font-family: var(--serif);
  font-size: 1.2rem;
  line-height: 1.55;
  max-width: var(--measure);
}

.more { margin-top: 2rem; }
.closing {
  font-family: var(--serif);
  font-size: 1.35rem;
  margin-top: 1.5rem;
}

/* ------------------------------------------------------------------
   lists
   ------------------------------------------------------------------ */

.list { max-width: var(--measure); }
.list li {
  padding: 0.85rem 0 0.85rem 1.5rem;
  border-bottom: 1px solid var(--rule-soft);
  position: relative;
}
.list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.55rem;
  width: 0.55rem;
  height: 1px;
  background: var(--olympic-gold);
}
.list li:last-child { border-bottom: 0; }

.list--unverified li { color: var(--ink-quiet); }
.list--elsewhere li { padding-left: 0; }
.list--elsewhere li::before { display: none; }
.elsewhere__text { display: block; color: var(--ink-quiet); font-size: 0.9375rem; }

/* ------------------------------------------------------------------
   call to action. Gold ground, blue text: 3.6:1 by ratio, which is why
   the label is set at 1.0625rem semibold, above the large-text
   threshold, and why gold appears nowhere else.
   ------------------------------------------------------------------ */

.cta {
  display: inline-block;
  margin-top: 2rem;
  padding: 0.95rem 1.6rem;
  background: var(--duke-blue);
  color: var(--surf-white);
  border: 1px solid var(--duke-blue);
  font-family: var(--sans);
  font-size: 1.0625rem;
  letter-spacing: 0.01em;
}
.cta:hover {
  background: var(--olympic-gold);
  border-color: var(--olympic-gold);
  color: #1a1409;
}
.cta__ext {
  display: inline-block;
  margin-left: 0.4em;
  font-size: 0.85em;
}
.cta--pending {
  background: transparent;
  color: var(--ink-quiet);
  border: 1px dashed var(--rule);
}

/* a sibling property that is not live yet: named, but not linked */
.sibling { font-family: var(--serif); }
.sibling--pending {
  color: var(--ink-quiet);
  border-bottom: 0;
}

/* ------------------------------------------------------------------
   figures and photograph slots
   ------------------------------------------------------------------ */

.figure { margin: 2.5rem 0 0; }
.figure__img { width: 100%; }

.figure__caption {
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--ink-quiet);
  max-width: 46ch;
}
.figure__credit { display: block; font-size: 0.8125rem; }

/* A photograph that does not exist yet is written down, not drawn as a hole.
   The first version was a hatched 3:2 box with an 11px label floating in the
   middle of it: six of those came to 43% of /room/ in empty rectangles, while
   the captions, which are the actual content, sat underneath at 15px grey.
   So the entry is inverted. The slot label is the eyebrow, the caption is the
   body, and the block is as tall as its own words. */
.figure--slot .figure__frame {
  border-top: 1px solid var(--rule);
  padding-top: 1.15rem;
}
/* Not uppercased, for the same reason .eyebrow is not: these labels carry
   Kalākaua, and text-transform is where the kahakō dies. The brand gate
   caught this one on the rendered page, which is the only place it shows. */
.figure__slotlabel {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--ink-quiet);
}
.figure--slot .figure__caption {
  margin-top: 0.55rem;
  font-family: var(--serif);
  font-size: 1.25rem;
  line-height: 1.45;
  color: var(--ink);
  max-width: 40ch;
}
.figure--slot .figure__credit {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--ink-quiet);
  margin-top: 0.4rem;
}
/* A register entry is a text block, so it obeys the measure like every other
   text block instead of spanning the full wrap. */
.figure--slot.figure--feature { max-width: var(--measure); margin-bottom: 0; }
.plates .figure--slot { margin: 0; }

.figure--inline { max-width: 46rem; }

/* A published photograph. Every landscape frame in this set is 2.16:1, so it
   runs the full content width and reads as a horizon across the column
   rather than as a plate in a grid. */
.figure--band { margin-top: clamp(2.5rem, 6vw, 4.5rem); }
.figure--band:first-child { margin-top: 0; }
.figure--band .figure__img { width: 100%; }
.figure--band .figure__caption {
  margin-top: 1rem;
  font-size: 1rem;
  max-width: var(--measure);
}
/* The one portrait in the set. A 1109x2400 frame at full width would be four
   screens tall, so it is held to the reading measure. */
.figure--tall { max-width: 30rem; }

/* The photo run on /room/: bleeds stacked, breathing, no side padding on the
   section itself or the breakout fights the wrap. */
.section--plates > .figure--bleed + .figure--bleed,
.section--plates > .wrap + .figure--bleed,
.section--plates > .figure--bleed + .wrap { margin-top: clamp(3rem, 7vw, 6rem); }
.section--plates > .wrap > .figure--tall { margin-top: 0; }

.plates {
  display: grid;
  gap: clamp(1.75rem, 4vw, 2.5rem);
  grid-template-columns: 1fr;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}
@media (min-width: 48rem) {
  .plates { grid-template-columns: repeat(2, 1fr); }
}
.figure--feature { margin-top: 0; }

/* ------------------------------------------------------------------
   visit blocks
   ------------------------------------------------------------------ */

.section--blocks .wrap {
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) {
  .section--blocks .wrap { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.block__head {
  font-family: var(--serif);
  font-size: 1.4rem;
  margin-bottom: 0.9rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--rule-soft);
}
.block__after { color: var(--ink-quiet); font-size: 0.9375rem; max-width: var(--measure); }
.block__link { font-size: 0.9375rem; }
.sep { padding: 0 0.4em; color: var(--rule); }

/* aloha@dukekahanamokugallery.com has a min-content width of 322px, which
   overflows a 320px viewport under the 1.4.12 text-spacing overrides. It gets
   worse when contact.emailLive flips and it becomes a link. */
[data-slot="email"],
a[href^="mailto"] { overflow-wrap: anywhere; }

.address {
  font-style: normal;
  font-family: var(--serif);
  font-size: 1.2rem;
  line-height: 1.5;
}
.address > span { display: block; }

/* The build wraps Hawaiian words in <span lang="haw">. A descendant selector
   anywhere will catch those spans: ".address span" turned
   "2365 Kalākaua Avenue" into three lines. The language wrapper is a semantic
   hook and must never change layout, so it is pinned here and every rule that
   styles a span must use the child combinator. */
[lang="haw"] { display: inline; }
.address__venue { color: var(--ink-quiet); font-size: 0.9375rem; font-family: var(--sans); }

/* ------------------------------------------------------------------
   the maker roster
   ------------------------------------------------------------------ */

.roster {
  margin-top: 2.5rem;
  display: grid;
  gap: 2rem;
  grid-template-columns: 1fr;
}
@media (min-width: 48rem) {
  .roster { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.roster__item {
  padding-top: 1.15rem;
  border-top: 1px solid var(--rule);
}
.roster__name {
  font-family: var(--serif);
  font-size: 1.35rem;
  line-height: 1.2;
}
.roster__where {
  font-size: 0.9375rem;
  color: var(--ink-quiet);
  margin: 0.3rem 0 0.8rem;
}
.roster__craft::before { content: "· "; }
.roster__line {
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.5;
  max-width: 38ch;
}
.roster__handle {
  font-size: 0.9375rem;
  color: var(--ink-quiet);
  margin-bottom: 0;
}

/* The five-line label, shown as the thing it is rather than described.
   It is the most important printed piece in the room, so the web version
   sets it in the same order with the same restraint. */
.label-example {
  margin: 1.75rem 0;
  padding: 1.5rem 1.75rem;
  background: rgba(223, 211, 195, 0.4);
  max-width: var(--measure);
}
.label-example__line { display: block; }
.label-example__line--0 {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  margin-bottom: 0.5rem;
}
.label-example__line--1 {
  font-family: var(--serif);
  font-size: 1.25rem;
  line-height: 1.25;
}
.label-example__line--2 {
  font-size: 0.9375rem;
  color: var(--ink-quiet);
  margin: 0.35rem 0 0.8rem;
}
.label-example__line--3 { font-size: 1rem; line-height: 1.6; }
.label-example__line--4 {
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--rule-soft);
  font-size: 0.9375rem;
}

/* ------------------------------------------------------------------
   press
   ------------------------------------------------------------------ */

/* Boilerplate is meant to be selected and pasted, so it is set to be read
   as a block of copy rather than styled as a quotation. */
.boilerplate {
  margin: 1.5rem 0;
  padding: 1.5rem 1.75rem;
  border-left: 2px solid var(--rule);
  background: rgba(223, 211, 195, 0.28);
  max-width: var(--measure);
}
.boilerplate p {
  margin: 0;
  font-family: var(--serif);
  font-size: 1.15rem;
  line-height: 1.6;
}

.factlist { margin-top: 1.5rem; max-width: var(--measure); }
.factrow {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.2rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule-soft);
}
@media (min-width: 34rem) {
  .factrow { grid-template-columns: 7rem 1fr; gap: 1.25rem; }
}
.factrow:last-child { border-bottom: 0; }
.factrow__k {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--ink-quiet);
  padding-top: 0.25rem;
}
.factrow__v { margin: 0; }

/* ------------------------------------------------------------------
   footer
   ------------------------------------------------------------------ */

.footer {
  background: var(--duke-blue);
  color: var(--surf-white);
  padding: clamp(3rem, 7vw, 4.5rem) 0 2.5rem;
  margin-top: var(--sect-y);
}
.footer a { border-bottom-color: rgba(237, 236, 230, 0.6); }
.footer :focus-visible { outline-color: var(--surf-white); }

.footer__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad-x);
  display: grid;
  gap: clamp(2rem, 5vw, 3rem);
  grid-template-columns: 1fr;
}
@media (min-width: 52rem) {
  .footer__inner { grid-template-columns: repeat(3, 1fr); }
}

.footer__head {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(237, 236, 230, 0.62);
  margin-bottom: 1rem;
}
.footer .address { font-size: 1.05rem; }
.footer .address__venue { color: rgba(237, 236, 230, 0.62); }
.footer__line { margin-bottom: 0.75rem; }
.footer__note {
  font-size: 1rem;
  color: rgba(237, 236, 230, 0.72);
  margin-top: 0.75rem;
}
.footer .sibling--pending {
  color: rgba(237, 236, 230, 0.72);
  border-bottom: 0;
}
.footer__social { display: flex; gap: 1rem; margin-top: 1rem; }

/* Press and 日本語 live here rather than in the primary nav: they are for
   two specific readers, and the top of the page belongs to the guest. */
.footer__nav {
  display: flex;
  justify-content: center;
  gap: 1.75rem;
  margin-bottom: 2rem;
  font-size: 0.9375rem;
}
.footer__nav a { padding-block: 0.4rem; display: inline-block; }

.footer__base {
  max-width: var(--wrap);
  margin: clamp(2.5rem, 6vw, 4rem) auto 0;
  padding: 2rem var(--pad-x) 0;
  border-top: 1px solid rgba(237, 236, 230, 0.18);
  text-align: center;
}
.footer__base .waterline { color: rgba(237, 236, 230, 0.35); }

/* The tagline is his line. Gold, EB Garamond, tracked wide, never in
   quotes, never with an exclamation mark, never rewritten. It is set at
   1.375rem so that gold on blue clears the large-text threshold. */
.footer__tagline {
  font-family: var(--serif);
  /* 24px. Gold on Duke Blue is 3.8:1, which clears the 3:1 large-text bar at
     24px or above at any weight, and fails the 4.5:1 normal-text bar below
     it. The first version was 22px, which is neither. Weight stays at 500
     because only 400 and 500 are loaded and 700 would be synthesised. */
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  color: var(--olympic-gold);
  text-transform: uppercase;
  margin-bottom: 0.4rem;
}
/* The tagline is his line, and an unattributed tagline on a commercial site
   reads as a slogan the gallery wrote. One line fixes that. */
.footer__attrib {
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: rgba(237, 236, 230, 0.55);
  margin-bottom: 1.5rem;
}

.footer__fine {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: rgba(237, 236, 230, 0.62);
  max-width: 52ch;
  margin-inline: auto;
}

/* ------------------------------------------------------------------
   the Japanese page
   ------------------------------------------------------------------ */

.page--ja { font-family: var(--ja); }
.page--ja .hero__headline,
.page--ja .section__head,
.page--ja .block__head,
.page--ja .hero__sub,
.page--ja .prose p,
.page--ja .lede { font-family: var(--ja); }
/* Japanese sets without word spaces, so it needs looser leading and it must
   not break mid-word the way the English rules assume. */
.page--ja .hero__headline { font-size: clamp(1.9rem, 6vw, 2.8rem); line-height: 1.35; }
.page--ja .prose p,
.page--ja .lede,
.page--ja .block__after { line-height: 1.9; }
.page--ja .hero__sub { line-height: 1.85; font-size: clamp(1.05rem, 2.2vw, 1.2rem); }
/* The street address stays in Latin script: it is what a taxi driver reads. */
.page--ja .address { font-family: var(--serif); }



/* ==================================================================
   Composition
   ------------------------------------------------------------------
   The first version of this file was written in August, when no
   photograph of the room existed and no photograph of Duke could ever
   be cleared. Type-led was the only option and it was the right one.

   Six photographs of the room exist now, so the page is built around
   them instead: full-bleed image bands break the reading column, the
   ground changes under your feet between sections, and the display
   scale is allowed to be a gallery's rather than a document's.

   Three grounds, in rotation: Surf White to read on, Waikīkī Sand to
   slow down on, Duke Blue to stop on. The restraint rule still holds,
   two brand colours plus one neutral on any single surface.
   ================================================================== */

/* A band that ignores the wrap and runs the full width of the window. */
.bleed {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  max-width: none;
}

/* A photograph at full width. Every landscape frame in this set is
   2.16:1, which is close to a cinema ratio, so edge to edge is the shape
   they were taken in. The caption stays in the reading column underneath,
   because a caption that runs 1440px wide is not a caption. */
.figure--bleed {
  margin: 0;
}
.figure--bleed .figure__img {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  max-height: 78vh;
  object-fit: cover;
}
/* The caption sits on the page's left spine, at reading width, not centred
   under the photograph and not running the full 1440. Aligning it to the
   same x as every heading is what stops a full-bleed page falling apart. */
.figure--bleed .figure__caption {
  max-width: var(--measure);
  margin-top: 1.15rem;
  margin-inline-start: max(var(--pad-x), calc((100vw - var(--wrap)) / 2 + var(--pad-x)));
  margin-inline-end: var(--pad-x);
}

/* Grounds. A page that is one colour from top to bottom has no pace. */
.section--dark {
  background: var(--duke-blue);
  color: var(--surf-white);
}
.section--dark .eyebrow,
.section--dark .orient__q { color: rgba(237, 236, 230, 0.66); }
.section--dark .orient__q { border-bottom-color: rgba(237, 236, 230, 0.22); }
.section--dark .section__head { color: var(--surf-white); }
.section--dark .waterline { color: rgba(237, 236, 230, 0.4); }
.section--dark a { border-bottom-color: rgba(237, 236, 230, 0.6); }
.section--dark :focus-visible { outline-color: var(--surf-white); }

.section--sand { background: var(--waikiki-sand); }
.section--sand .aside { background: rgba(237, 236, 230, 0.55); }

/* The section rule is for two light sections meeting. Where the ground
   changes, the change is the divider. */
.section--dark + .section,
.section--sand + .section,
.section + .section--dark,
.section + .section--sand,
.figure--bleed + .section { border-top: 0; }

/* ------------------------------------------------------------------
   The editorial two column
   ------------------------------------------------------------------
   The old layout put every heading directly above its own paragraph in
   one 30rem column, which at 1440 used a third of the window and left
   the rest empty. The heading now sits in its own column and stays with
   you while the prose scrolls past it. */

@media (min-width: 62rem) {
  .editorial {
    display: grid;
    grid-template-columns: minmax(14rem, 20rem) minmax(0, var(--measure));
    gap: clamp(3rem, 7vw, 6rem);
    align-items: start;
  }
  .editorial__aside {
    position: sticky;
    top: clamp(2rem, 6vw, 5rem);
  }
  .editorial__aside .section__head { max-width: 14ch; }
  .editorial__body { max-width: var(--measure); }
}
.editorial__aside .waterline { margin-bottom: 0; }

/* ------------------------------------------------------------------
   The hero, given something to be asymmetric about
   ------------------------------------------------------------------ */

@media (min-width: 62rem) {
  .hero--split .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    gap: clamp(3rem, 6vw, 5rem);
    align-items: end;
  }
  /* 12ch forced "Six photographs, three still to take" onto four lines. */
  .hero--split .hero__headline { max-width: 15ch; }
  .hero--split .hero__sub { margin-top: 0; padding-bottom: 0.6rem; }
  .hero--split .eyebrow,
  .hero--split .hero__headline,
  .hero--split .waterline { grid-column: 1; }
  .hero--split .hero__sub { grid-column: 2; grid-row: 1 / span 3; }
}

/* A gallery headline on a 1440 screen was capping at 62px, which reads as
   a document rather than a room. */
.hero--split .hero__headline,
.hero--home .hero__headline {
  font-size: clamp(2.6rem, 7.2vw, 5.6rem);
  line-height: 1.02;
  letter-spacing: -0.015em;
}

/* The line that carries the page, set to be read across a room. */
.statement {
  font-family: var(--serif);
  font-size: clamp(1.75rem, 4.4vw, 3.1rem);
  line-height: 1.22;
  letter-spacing: -0.01em;
  max-width: 20ch;
  margin: 0;
}
.statement + .statement__after {
  margin-top: 1.75rem;
  max-width: var(--measure);
  color: rgba(237, 236, 230, 0.78);
}



/* ==================================================================
   Motion and continuity
   ------------------------------------------------------------------
   All of this is CSS. The site still ships zero JavaScript.

   Two modern features do the work that a framework is usually hired
   for. Cross-document view transitions carry the masthead and the
   page ground across a navigation, so moving between pages reads as
   one continuous thing rather than seven separate documents.
   Scroll-driven animations bring each photograph and section up as it
   enters, on the compositor, with no scroll listener.

   FAIL-SAFE, and this matters: every hidden initial state lives
   INSIDE @supports and OUTSIDE prefers-reduced-motion. A browser that
   cannot run these simply shows the finished state. Nothing is ever
   hidden by a rule whose reveal might not fire.
   ================================================================== */

@view-transition { navigation: auto; }

@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation-duration: 260ms; }
  ::view-transition-new(root) { animation-duration: 260ms; }

  /* The masthead is the same object on every page, so it should not
     cross-fade with the body. Naming it holds it still. */
  .masthead { view-transition-name: masthead; }
  .footer { view-transition-name: sitefooter; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rise {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 62%;
    }
    /* Transform only, no opacity. A photograph is allowed to fade in because
       @supports has already told us the timeline works. Words are not: if a
       reveal ever failed to advance, opacity 0 text would be unreadable and
       there would be no way for the reader to know it was there. A stuck
       transform is merely a few pixels low. */
    @keyframes rise {
      from { transform: translateY(1.75rem); }
      to   { transform: none; }
    }

    /* A photograph settles into place: it scales down slightly as it enters.
       TRANSFORM ONLY, and this is deliberate rather than timid.

       The first version faded from opacity 0. I could not verify the reveal
       actually completes, because this environment's browser never advances a
       view() timeline (animationProgress stayed at 0 with the element centred
       in the viewport, which could equally have been the harness or a real
       bug in the rule). An unverifiable opacity reveal on a live site for an
       open business has one failure mode: blank photographs, for everyone,
       with nothing on the page to suggest anything is missing.

       A stuck transform shows the photograph 4% large. Nobody will ever
       notice, and it cannot fail closed. Put the opacity back only after
       watching the reveal run in a real browser. */
    .figure--bleed .figure__img {
      animation: settle linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 70%;
    }
    @keyframes settle {
      from { transform: scale(1.04); }
      to   { transform: none; }
    }
    /* The one above the fold is already in view on load, so it must not
       start hidden. */
    .figure--bleed:first-of-type .figure__img,
    .hero + .figure--bleed .figure__img { animation: none; }
  }
}

/* ------------------------------------------------------------------
   The masthead, which was a static bar
   ------------------------------------------------------------------ */

.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  /* Not fully opaque: the page moves underneath it and you can tell. */
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.2) blur(10px);
  -webkit-backdrop-filter: saturate(1.2) blur(10px);
}
@supports not (backdrop-filter: blur(4px)) {
  .masthead { background: var(--bg); }
}

/* ------------------------------------------------------------------
   Typographic craft
   ------------------------------------------------------------------ */

/* Headings break where the meaning is, not where the box ends. */
.hero__headline,
.section__head,
.statement,
.aside__head,
.block__head { text-wrap: balance; }

/* No orphans at the end of a paragraph. */
.prose p, .lede, .orient__a, .figure__caption { text-wrap: pretty; }

/* EB Garamond has real oldstyle figures. Dates and street numbers are
   most of this site, and lining figures in a serif look like a
   spreadsheet. Tabular where things align, proportional in prose. */
.prose, .lede, .hero__sub, .statement, .address, .boilerplate {
  font-variant-numeric: oldstyle-num proportional-nums;
}
.factrow__v, .factlist { font-variant-numeric: lining-nums tabular-nums; }

/* Duke Blue rather than gold: gold is spent on five surfaces already and a
   selection highlight is not worth the sixth. 9.97:1 either way. */
::selection { background: var(--duke-blue); color: var(--surf-white); }
.section--dark ::selection { background: var(--surf-white); color: var(--duke-blue); }

/* ------------------------------------------------------------------
   Plate numbers
   ------------------------------------------------------------------
   A gallery numbers what it hangs. It also gives a visitor something
   to point at when they write in about one. */

.plate-no {
  display: block;
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--ink-quiet);
  margin-bottom: 0.4rem;
}
.section--dark .plate-no { color: rgba(237, 236, 230, 0.66); }

/* ------------------------------------------------------------------
   The section index on the long page
   ------------------------------------------------------------------ */

.index {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  padding-block: 1.1rem;
}
.index__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.75rem;
  font-size: 0.9375rem;
}
.index__list a {
  border-bottom: 0;
  display: inline-block;
  padding-block: 0.35rem;
}
.index__list a:hover { border-bottom: 1px solid currentColor; }
.index__no {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  color: var(--ink-quiet);
  margin-right: 0.5rem;
}
/* Anchor targets must clear the sticky masthead. */
:where(section[id]) { scroll-margin-top: 6rem; }

/* ------------------------------------------------------------------
   Questions
   ------------------------------------------------------------------ */

.qa { max-width: var(--measure); }
.qa__q {
  font-family: var(--serif);
  font-size: 1.25rem;
  line-height: 1.3;
  margin-top: 1.9rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule-soft);
}
.qa__q:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.qa__a { margin: 0.55rem 0 0; }

/* ------------------------------------------------------------------
   404
   ------------------------------------------------------------------ */

.hero--404 { min-height: 52vh; display: grid; align-content: center; }

/* ------------------------------------------------------------------
   print. People print directions.
   ------------------------------------------------------------------ */

@media print {
  .masthead, .nav, .cta, .waterline { display: none; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .footer { background: #fff; color: #000; padding-top: 1rem; }
  .footer__fine, .footer__note, .footer__head { color: #333; }
  .figure--slot { display: none; }
  a { border: 0; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }
}
