/* Sepiabox visual identity (docs/architecture.md): colours and typefaces. Desktop first; phones only need to work. */

/* Typefaces are served from wwwroot/fonts (SIL Open Font License, see the OFL.txt files), not a font CDN (D-040). */
@font-face {
    font-family: "Bricolage Grotesque";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("fonts/bricolage-grotesque/bricolage-grotesque-latin-500-normal.woff2") format("woff2");
}

@font-face {
    font-family: "Bricolage Grotesque";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("fonts/bricolage-grotesque/bricolage-grotesque-latin-700-normal.woff2") format("woff2");
}

/* ExtraBold for the wordmark and the big numbers. */
@font-face {
    font-family: "Bricolage Grotesque";
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url("fonts/bricolage-grotesque/bricolage-grotesque-latin-800-normal.woff2") format("woff2");
}

@font-face {
    font-family: "Figtree";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("fonts/figtree/figtree-latin-400-normal.woff2") format("woff2");
}

@font-face {
    font-family: "Figtree";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("fonts/figtree/figtree-latin-500-normal.woff2") format("woff2");
}

@font-face {
    font-family: "Figtree";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("fonts/figtree/figtree-latin-600-normal.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
}

@font-face {
    font-family: "IBM Plex Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
}
/* The brand's colours by their names (docs/architecture.md): sepia is the brand, cyanotype the actions,
   developer (the darkest brown, as in photographic developer) the text, silver paper the background, mat the lines.
   The rest are the brand board's supporting tones: surfaces, secondary text and the filter chips. */
:root {
    --sepia: #9a5a2c;
    --cyanotype: #1f4c74;
    --cyanotype-hover: #163a59;
    --developer: #231a14;
    --silver-paper: #eeece7;
    --mat: #d8d1c6;
    --surface: #f8f7f4;
    --text-secondary: #5c5048;
    --chip: #e6ebf0;
    --white: #ffffff;
    --font-display: "Bricolage Grotesque", system-ui, sans-serif;
    --font-body: "Figtree", system-ui, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, monospace;
}

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

body {
    margin: 0;
    background: var(--silver-paper);
    color: var(--developer);
    font-family: var(--font-body);
    line-height: 1.5;
}

a {
    color: var(--cyanotype);
}

a:hover {
    color: var(--cyanotype-hover);
}

h1, h2 {
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.2;
}

h1:focus {
    outline: none;
}

/* An author display rule (flex, grid) beats the hidden attribute, so an element made visible by a script only would show without it. */
[hidden] {
    display: none !important;
}

.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.mono {
    font-family: var(--font-mono);
}

.muted {
    color: var(--text-secondary);
}

.small {
    font-size: 0.875rem;
}

.top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 24px;
    padding: 12px 24px;
    background: var(--white);
    border-bottom: 1px solid var(--mat);
}

.brand {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-right: 16px;
    color: var(--developer);
    text-decoration: none;
}

/* The logo keeps its colours: the links' hover would turn "box" blue. */
.brand:hover {
    color: var(--developer);
}

/* The wordmark (sepiabox-brand): lowercase, ExtraBold, tight, "sepia" in the brand colour and "box" in developer. */
.wordmark {
    font-family: var(--font-display);
    font-size: 1.375rem;
    font-weight: 800;
    letter-spacing: -0.045em;
    line-height: 1;
}

.wordmark-sepia {
    color: var(--sepia);
}

main {
    max-width: 1440px;
    margin: 0 auto;
    padding: 16px 24px 48px;
}

.month h2 {
    margin: 32px 0 12px;
    font-size: 1.25rem;
}

/* The occasions of a search by part of a photo are headed like months; the heading above them is quieter. */
.month h3 {
    margin: 32px 0 12px;
    font-family: var(--font-display);
    font-size: 1.25rem;
    line-height: 1.2;
}

.region-heading {
    margin: 16px 0 0;
    font-size: 1rem;
    font-weight: 600;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.thumb {
    position: relative;
    display: block;
    aspect-ratio: 1;
    overflow: hidden;
    background: var(--mat);
    border-radius: 2px;
}

.thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.thumb:focus-visible {
    outline: 3px solid var(--cyanotype);
    outline-offset: 2px;
}

.placeholder {
    display: grid;
    place-items: center;
    height: 100%;
    padding: 8px;
    font-size: 0.8rem;
    text-align: center;
}

.badge {
    position: absolute;
    right: 6px;
    bottom: 6px;
    padding: 1px 6px;
    background: var(--developer);
    color: var(--white);
    font-family: var(--font-mono);
    font-size: 0.7rem;
    border-radius: 2px;
}

.play {
    position: absolute;
    top: 50%;
    left: 50%;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: -20px 0 0 -20px;
    /* The same brown, for browsers without color-mix. */
    background: rgb(35 26 20 / 0.7);
    background: color-mix(in srgb, var(--developer) 70%, transparent);
    color: var(--white);
    border-radius: 50%;
    pointer-events: none;
}

.play svg {
    fill: currentColor;
}

/* The filter bar (S-013): labelled selects in a row that wraps on narrow screens. */
.filters,
.ask {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 16px;
    margin: 8px 0 16px;
}

/* The status line is always in the page, so a screen reader announces what ask.js puts in it (D-101); it is only clipped away
   while there is nothing to say. */
.ask-status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

.ask.busy .ask-status,
.ask.failed .ask-status {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
    flex-basis: 100%;
    color: var(--cyanotype);
}

.ask.busy .ask-status::before {
    content: "";
    display: inline-block;
    width: 0.9em;
    height: 0.9em;
    margin-right: 0.5em;
    vertical-align: -0.1em;
    border: 2px solid currentcolor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: ask-spin 0.9s linear infinite;
}

@keyframes ask-spin {
    to {
        transform: rotate(360deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .ask.busy .ask-status::before {
        animation: none;
    }
}

.ask.failed .ask-status {
    color: var(--sepia);
}

.ask button[aria-disabled="true"] {
    opacity: 0.6;
    cursor: progress;
}

.filters label,
.ask label {
    display: grid;
    gap: 4px;
    font-size: 0.85rem;
}

.filters select,
.filters button,
.ask button {
    min-height: 36px;
    padding: 4px 8px;
    font: inherit;
    border: 1px solid var(--mat);
    border-radius: 2px;
    background: var(--white);
    color: var(--developer);
}

.filters input[type="search"],
.ask input[type="search"] {
    min-height: 36px;
    min-width: 16rem;
    padding: 4px 8px;
    font: inherit;
    border: 1px solid var(--mat);
    border-radius: 2px;
}

.filters button,
.ask button {
    background: var(--cyanotype);
    border-color: var(--cyanotype);
    color: var(--white);
    cursor: pointer;
}

.filters button:hover:not(:disabled),
.ask button:hover:not(:disabled) {
    background: var(--cyanotype-hover);
    border-color: var(--cyanotype-hover);
}

.filters button:disabled,
.ask button:disabled,
.button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.filters .shortcut[aria-current="page"] {
    font-weight: 600;
}

/* The question box (S-025) shares the filter bar's look; the question gets the width. */
.ask {
    margin-bottom: 0;
}

.ask label {
    flex: 1 1 24rem;
}

.ask input[type="search"] {
    width: 100%;
}

.ask .hint {
    flex-basis: 100%;
    margin: 0;
    font-size: 0.85rem;
}

/* A counting answer (S-026): the number first, large. */
.answer {
    margin: 0 0 24px;
}

.answer .number {
    margin: 0;
    color: var(--sepia);
    font-family: var(--font-display);
    font-size: 3rem;
    font-weight: 800;
    letter-spacing: -0.04em;
    line-height: 1.1;
}

.answer .sentence {
    margin: 4px 0 8px;
    font-size: 1.1rem;
}

.answer .ranking {
    border-collapse: collapse;
    min-width: 16rem;
}

.answer .ranking th,
.answer .ranking td {
    padding: 4px 12px 4px 0;
    text-align: left;
}

.answer .ranking td {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* What a search applies, each part removable: filters are set in the mono face on the cyanotype tint. */
.chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0 0 16px;
    font-size: 0.9rem;
}

.chips ul {
    display: contents;
    list-style: none;
}

.chips li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 4px 2px 10px;
    border-radius: 999px;
    background: var(--chip);
    color: var(--cyanotype);
    font-family: var(--font-mono);
    font-size: 0.85rem;
}

.chips li a {
    display: inline-grid;
    place-items: center;
    min-width: 24px;
    min-height: 24px;
    border-radius: 999px;
    text-decoration: none;
}

.more {
    margin-top: 32px;
}

.pages {
    display: flex;
    justify-content: space-between;
    margin-top: 32px;
}

.empty {
    margin-top: 48px;
}

.back {
    margin: 0 0 16px;
}

.detail {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
    gap: 32px;
    align-items: start;
}

.preview {
    margin: 0;
    background: var(--white);
    border: 1px solid var(--mat);
    min-height: 240px;
}

.preview img,
.preview video {
    display: block;
    width: 100%;
    height: auto;
}

/* The larger previews of an index-only photo (2048 px) must not push the facts off a tall screen. */
.preview img {
    max-height: 85vh;
    object-fit: contain;
}

.preview video {
    max-height: 80vh;
    background: var(--developer);
}

/* "Photos like this part of a photo" (S-041): the rectangle is drawn over the preview, in pixels set by region.js. */
.region-frame {
    position: relative;
}

.region-frame.selecting {
    cursor: crosshair;
    touch-action: none;
    user-select: none;
}

.region-frame.selecting {
    outline: 3px dashed var(--developer);
    outline-offset: -3px;
}

.region-tools .button[aria-pressed="true"] {
    outline: 3px solid var(--developer);
    outline-offset: 2px;
}

.region-frame:focus-visible {
    outline: 3px solid var(--developer);
    outline-offset: -3px;
}

.region-box {
    position: absolute;
    box-sizing: border-box;
    border: 2px solid var(--white);
    outline: 2px solid var(--developer);
    background: color-mix(in srgb, var(--white) 18%, transparent);
    pointer-events: none;
}

.region-tools {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    align-items: center;
    padding: 12px 16px;
}

.region-tools form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    align-items: center;
}

/* Without the script every control in it is hidden; the padding alone would leave a gap under the photo. */
.region-tools:not(:has(> :not([hidden]))) {
    display: none;
}

.region-status:empty {
    display: none;
}

.region-tools p {
    margin: 0;
}

.player-error {
    margin: 0;
    padding: 12px 16px;
    font-weight: 600;
}

.player-error:empty {
    display: none;
}

.processing {
    margin: 0;
    padding: 16px;
    font-weight: 600;
}

.facts h1 {
    margin-top: 0;
    font-size: 1.5rem;
}

.facts h2 {
    font-size: 1.05rem;
    margin-top: 24px;
}

.facts dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 16px;
}

.facts dt {
    font-weight: 600;
}

.facts dd {
    margin: 0;
}

/* Names and paths may break anywhere, but only when they do not fit (not mid-word in a sentence that does). */
.sources {
    padding-left: 18px;
    overflow-wrap: anywhere;
}

.source-name {
    font-weight: 600;
}

.source-link {
    display: inline-block;
    margin-left: 8px;
}

.button {
    display: inline-block;
    padding: 8px 16px;
    background: var(--cyanotype);
    color: var(--white);
    text-decoration: none;
    border: 0;
    border-radius: 4px;
    font: inherit;
    cursor: pointer;
}

.button:hover:not(:disabled) {
    background: var(--cyanotype-hover);
    color: var(--white);
}

.top-end {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    margin-left: auto;
}

.user {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 11rem;
    white-space: nowrap;
}

.sign-out {
    margin: 0;
}

.language {
    display: flex;
    gap: 4px;
    margin: 0;
}

.language button {
    padding: 4px 8px;
    background: none;
    color: var(--cyanotype);
    border: 1px solid transparent;
    border-radius: 4px;
    font: inherit;
    font-size: 0.875rem;
    cursor: pointer;
}

.language button[aria-pressed="true"] {
    color: var(--developer);
    border-color: var(--mat);
    cursor: default;
}

.sign-out button {
    padding: 4px 12px;
    background: none;
    color: var(--cyanotype);
    border: 1px solid var(--mat);
    border-radius: 4px;
    font: inherit;
    cursor: pointer;
}

.auth {
    max-width: 420px;
    margin: 48px auto;
    padding: 24px;
    background: var(--white);
    border: 1px solid var(--mat);
    border-radius: 4px;
}

.auth .providers {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.auth .providers .sign-out {
    margin: 0;
}

.dev-login {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.dev-login input {
    padding: 8px;
    font: inherit;
    border: 1px solid var(--mat);
    border-radius: 4px;
}

@media (max-width: 800px) {
    .detail {
        grid-template-columns: 1fr;
    }

    main {
        padding: 12px 16px 32px;
    }
}

.language button,
.sign-out button {
    white-space: nowrap;
}

.error {
    padding: 8px 12px;
    color: var(--sepia);
    border: 1px solid var(--sepia);
    border-radius: 4px;
}

.nav-link {
    color: var(--developer);
    font-weight: 600;
    text-decoration: none;
}

.nav-link[aria-current="page"],
.nav-more-active {
    color: var(--cyanotype);
    text-decoration: underline;
    text-underline-offset: 4px;
}

/* The pages used now and then, behind a disclosure that needs no JavaScript (D-102); not .more, which the "Show more" line of a search uses. */
.nav-more {
    position: relative;
}

.nav-more > summary {
    cursor: pointer;
    list-style: none;
}

.nav-more > summary::-webkit-details-marker {
    display: none;
}

.nav-more > summary::after {
    content: " ▾" / "";
}

.nav-more-current {
    font-weight: 400;
}

.nav-more-list {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 20;
    display: grid;
    gap: 2px;
    min-width: 11rem;
    max-width: calc(100vw - 32px);
    padding: 8px;
    background: var(--white);
    border: 1px solid var(--mat);
    border-radius: 4px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.nav-more-list .nav-link {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
}

/* On a phone the list opens in the flow of the header, not over the page, so it cannot run off the screen. */
@media (max-width: 600px) {
    .nav-more[open] {
        flex-basis: 100%;
    }

    .nav-more-list {
        position: static;
        margin-top: 8px;
        max-width: none;
        box-shadow: none;
    }
}

.nav-link:hover,
.nav-link:focus-visible {
    color: var(--cyanotype);
    text-decoration: underline;
}

/* The people page (S-019): one card per person, the face cropped from its thumbnail by an inline style. */
.page-heading {
    margin: 24px 0 16px;
    font-size: 1.5rem;
}

.people {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 16px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.person {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.person .face {
    position: relative;
    display: block;
    aspect-ratio: 1;
    overflow: hidden;
    background: var(--mat);
    border-radius: 50%;
}

.person .face img {
    position: absolute;
    max-width: none;
}

.person .name {
    font-weight: 600;
}

/* A person's page (S-020): the corrections above the faces. */
.person-link {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: inherit;
    text-decoration: none;
}

.person-edit {
    display: flex;
    flex-wrap: wrap;
    gap: 16px 32px;
    align-items: flex-end;
    margin: 16px 0 24px;
}

.person-edit form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-end;
    margin: 0;
}

.person-edit label {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.person-faces button {
    font: inherit;
    padding: 2px 6px;
    border: 1px solid var(--mat);
    border-radius: 4px;
    background: var(--white);
    color: var(--developer);
    cursor: pointer;
}

.note {
    padding: 8px 12px;
    border-left: 3px solid var(--cyanotype);
    background: var(--white);
}

/* The occasions page (S-023): a card per occasion, three thumbnails over its title. */
.occasions {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 20px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.occasion-link {
    display: flex;
    flex-direction: column;
    gap: 6px;
    color: inherit;
    text-decoration: none;
}

.occasion-thumbs {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2px;
    min-height: 90px;
    background: var(--mat);
    border-radius: 2px;
    overflow: hidden;
}

.occasion-thumbs img {
    display: block;
    width: 100%;
    /* The img's height attribute would otherwise win over the aspect ratio and give tall strips. */
    height: auto;
    aspect-ratio: 1;
    object-fit: cover;
}

.occasion-thumbs .placeholder {
    grid-column: 1 / -1;
    min-height: 100px;
}

.occasion-filter {
    margin-bottom: 24px;
}

.occasion-link:focus-visible {
    outline: 3px solid var(--cyanotype);
    outline-offset: 4px;
    border-radius: 2px;
}

.occasion-link:hover .occasion-title {
    color: var(--cyanotype);
    text-decoration: underline;
}

.occasion-title {
    font-family: var(--font-display);
    font-weight: 600;
}

/* The storage page (S-028): a table like a count's ranking, and the assets under it in the timeline's grid. */
.storage-totals table {
    border-collapse: collapse;
}

.storage-totals th,
.storage-totals td {
    padding: 4px 16px 4px 0;
    text-align: left;
}

.storage-totals thead th:not(:first-child) {
    text-align: right;
}

.storage-totals td {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.storage-totals tfoot th,
.storage-totals tfoot td {
    border-top: 1px solid var(--mat);
    font-weight: 700;
}

.storage-assets {
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
}

/* A drive's name can be long and unbroken: wrap it anywhere and keep three lines (the full list is the title). */
.storage-assets p {
    margin: 4px 0 0;
    overflow-wrap: anywhere;
}

.storage-assets .clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}

.storage-assets .size {
    font-variant-numeric: tabular-nums;
}

.organize-views {
    display: flex;
    gap: 16px;
    margin: 12px 0;
}

.organize-form .organize-submit {
    margin-top: 24px;
}

.organize-form .grid {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
}

.bulk {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 8px 0 16px;
}

.burst h2 {
    margin: 24px 0 8px;
    font-size: 1.1rem;
}

.organize-item {
    position: relative;
    display: grid;
    gap: 2px;
}

.organize-item input {
    width: 22px;
    height: 22px;
    margin: 0;
}

.organize-item .check {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    cursor: pointer;
}

.sharpest-badge {
    position: absolute;
    top: 6px;
    left: 6px;
    padding: 1px 8px;
    background: var(--developer);
    color: var(--white);
    font-size: 0.8rem;
    border-radius: 2px;
    pointer-events: none;
}

/* The connected accounts (S-037): one block per account, its counts and its actions. */
.connections {
    display: grid;
    gap: 16px;
    margin: 0 0 16px;
    padding: 0;
    list-style: none;
}

.connection {
    padding: 16px;
    background: var(--white);
    border: 1px solid var(--mat);
    border-radius: 4px;
}

.connection p {
    margin: 0 0 8px;
}

.connection-account {
    overflow-wrap: anywhere;
}

.connection-account .status {
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.8rem;
    background: var(--chip);
    color: var(--cyanotype);
}

.connection-account .status-expired {
    background: transparent;
    border: 1px solid var(--sepia);
    color: var(--sepia);
}

.connection .counts span {
    margin-right: 16px;
}

.connection-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 12px;
    align-items: center;
}

.button.secondary {
    background: transparent;
    color: var(--cyanotype);
    border: 1px solid var(--cyanotype);
}

.button.secondary:hover:not(:disabled) {
    background: var(--chip);
    color: var(--cyanotype-hover);
}
