@charset "UTF-8";
/* =========================================================================
   Hugo Rosa — Photography
   Space Indigo ground, Platinum type, Lavender Grey for the quiet parts,
   Flag Red for anything you can act on. Photographs lead; the interface
   stays out of their way, photostream style.
   ========================================================================= */

/* --- Fonts ---------------------------------------------------------------- */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-024F, U+1E00-1EFF, U+0304, U+0308, U+0329;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-024F, U+1E00-1EFF, U+0304, U+0308, U+0329;
}

/* --- Hidden means hidden ------------------------------------------------- */

/* The browser's own [hidden] rule is the weakest there is: any class that
   sets display beats it, and the element stays on screen while every script
   believes it gone. That happened six times here, one rule at a time — the
   uncensored side of the comparison, the restore form on every sheet, and the
   blurred-faces mark on photographs with no face blurred at all. Said once,
   for everything, it cannot happen a seventh time. */
[hidden] { display: none !important; }

/* --- Tokens --------------------------------------------------------------- */

:root {
  color-scheme: dark;

  /* Space Indigo #2B2D42 anchors the ramp: darker below it, lighter above. */
  --ink-900: #14151F;
  --ink-800: #1B1D2B;
  --ink-700: #2B2D42;
  --ink-600: #353751;
  --ink-500: #414462;
  --ink-400: #4E5273;

  --line: rgba(141, 153, 174, 0.20);
  --line-strong: rgba(141, 153, 174, 0.38);

  /* Platinum for reading, Lavender Grey for everything quieter. */
  --text: #EDF2F4;
  --text-2: #B6C0D0;
  --text-3: #8D99AE;

  /* Flag Red fills, Strawberry for larger accents, a lighter tint where small
     red text has to clear 4.5:1 on the indigo ground. */
  --red-300: #FF6B7E;
  --red-400: #EF233C;
  --red-450: #E81838;
  --red-500: #D90429;
  --red-600: #C10425;
  --red-tint: rgba(239, 35, 60, 0.14);
  --red-tint-2: rgba(239, 35, 60, 0.30);

  --blue: #8FA6FF;
  --blue-tint: rgba(143, 166, 255, 0.18);

  --ok: #6FC3A0;
  --ok-tint: rgba(111, 195, 160, 0.14);
  --warn: #E0B15E;
  --warn-tint: rgba(224, 177, 94, 0.14);

  --font-display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-body: 'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  --step--1: 0.8125rem;
  --step-0: 1rem;
  --step-1: 1.125rem;
  --step-2: clamp(1.25rem, 1.05rem + 0.8vw, 1.5rem);
  --step-3: clamp(1.5rem, 1.2rem + 1.4vw, 2.125rem);
  --step-4: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  --step-5: clamp(2.5rem, 1.6rem + 4vw, 4.5rem);

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --space-9: 6rem;
  --space-10: 8rem;

  --r-1: 2px;
  --r-2: 4px;
  --r-3: 8px;
  --r-4: 14px;
  --r-full: 999px;

  --shell: 1560px;
  --reading: 68ch;
  --gap: 10px;

  --header-h: 76px;

  --ease: cubic-bezier(0.22, 0.61, 0.30, 1);
  --fast: 160ms;
  --base: 240ms;
  --slow: 420ms;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-2: 0 10px 30px rgba(0, 0, 0, 0.45);
  --shadow-3: 0 24px 60px rgba(0, 0, 0, 0.55);
}

@media (min-width: 900px) {
  :root {
    --header-h: 88px;
    --gap: 12px;
  }
}

/* --- Base ----------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ink-800);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

body.is-locked {
  overflow: hidden;
}

img,
picture,
svg {
  display: block;
  max-width: 100%;
}

h1, h2, h3, h4 {
  margin: 0 0 0.5em;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.025em;
}

h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }

p { margin: 0 0 1em; }

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

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

::selection {
  background: var(--red-tint-2);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

/* --- Layout --------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1rem, 3.5vw, 2.75rem);
}

.shell--narrow { max-width: 1120px; }

.section { padding-block: clamp(3rem, 7vw, 6rem); }
.section--tight { padding-block: clamp(2rem, 4vw, 3rem); }

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

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

.skip-link {
  position: fixed;
  top: -120px;
  left: 1rem;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--red-500);
  color: #fff;
  border-radius: var(--r-2);
  font-weight: 600;
  transition: top var(--base) var(--ease);
}

.skip-link:focus { top: 1rem; }

.eyebrow {
  display: block;
  margin-bottom: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--red-300);
}

.lede {
  font-size: var(--step-1);
  line-height: 1.65;
  color: var(--text-2);
  max-width: var(--reading);
}

.muted { color: var(--text-2); }
.tiny { font-size: var(--step--1); color: var(--text-3); }

/* --- Header --------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--ink-800);
  border-bottom: 1px solid var(--line);
  transition: background var(--base) var(--ease), border-color var(--base) var(--ease);
}

.site-header--overlay {
  position: fixed;
  inset: 0 0 auto;
  background: transparent;
  border-bottom-color: transparent;
}

.site-header--overlay::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(20, 21, 31, 0.72), rgba(20, 21, 31, 0));
  pointer-events: none;
  transition: opacity var(--base) var(--ease);
}

.site-header--overlay.is-scrolled {
  background: rgba(27, 29, 43, 0.92);
  backdrop-filter: blur(14px) saturate(140%);
  border-bottom-color: var(--line);
}

.site-header--overlay.is-scrolled::before { opacity: 0; }

.site-header__inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  height: var(--header-h);
}

.brand {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

.brand img {
  height: 34px;
  width: auto;
}

@media (min-width: 900px) {
  .brand img { height: 40px; }
}

.nav {
  display: none;
  align-items: center;
  gap: clamp(0.125rem, 0.4vw, 0.75rem);
}

/* The page you are on sits inside a whole hairline border, and a pointer over
   a link lightens its ground: no line under one edge. The letter-spacing
   leaves a gap after the last letter, so the right padding gives it back.
   The side padding narrows towards 900px, where the Spanish words only just
   fit on one line beside the logo and the languages. */
.nav__link {
  --nav-pad: clamp(0.375rem, 1.2vw - 0.4rem, 0.6rem);
  padding: 0.45rem calc(var(--nav-pad) - 0.05em) 0.45rem calc(var(--nav-pad) + 0.05em);
  border: 1px solid transparent;
  white-space: nowrap;
  border-radius: var(--r-2);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-2);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease),
    border-color var(--fast) var(--ease);
}

.nav__link:hover,
.nav__link:focus-visible {
  background: rgba(237, 242, 244, 0.07);
  color: var(--text);
}

.nav__link[aria-current='page'] {
  border-color: var(--line-strong);
  color: var(--text);
}

.header__side {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.lang {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
}

.lang a {
  padding: 0.3rem 0.6rem;
  border-radius: var(--r-full);
  font-family: var(--font-display);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--text-3);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.lang a:hover { color: var(--text); }

.lang a[aria-current='true'] {
  background: var(--red-tint);
  color: var(--red-300);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--fast) var(--ease);
}

.nav-toggle:hover { border-color: var(--line-strong); }

@media (min-width: 900px) {
  .nav { display: flex; }
  .nav-toggle { display: none; }
}

/* Mobile menu */

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  grid-template-rows: var(--header-h) 1fr;
  background: var(--ink-900);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--base) var(--ease), visibility var(--base) var(--ease);
}

.mobile-menu.is-open {
  visibility: visible;
  opacity: 1;
}

.mobile-menu__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.mobile-menu__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2);
  padding-bottom: var(--space-9);
}

.mobile-menu__link {
  padding: 0.6rem 0;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 8vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
  opacity: 0;
  transform: translateY(12px);
}

.mobile-menu.is-open .mobile-menu__link {
  animation: menu-in var(--slow) var(--ease) forwards;
}

.mobile-menu__link:nth-child(1) { animation-delay: 40ms; }
.mobile-menu__link:nth-child(2) { animation-delay: 80ms; }
.mobile-menu__link:nth-child(3) { animation-delay: 120ms; }
.mobile-menu__link:nth-child(4) { animation-delay: 160ms; }
.mobile-menu__link:nth-child(5) { animation-delay: 200ms; }

.mobile-menu__link[aria-current='page'] { color: var(--red-300); }

.mobile-menu__foot {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

@keyframes menu-in {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* --- Buttons -------------------------------------------------------------- */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-border: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0 1.5rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-border);
  border-radius: var(--r-2);
  font-family: var(--font-body);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
    color var(--fast) var(--ease), opacity var(--fast) var(--ease);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Working (app.js, «Busy buttons»): the pressed button keeps its colour and
   spins, so it reads as busy rather than as switched off. An icon button shows
   the spinner in place of its icon. */
.btn.is-loading,
.btn.is-loading:disabled,
.icon-btn.is-loading {
  opacity: 1;
  cursor: progress;
  pointer-events: none;
}

.btn.is-loading::before,
.icon-btn.is-loading::before {
  content: "";
  flex: none;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: busy-spin 0.7s linear infinite;
}

.icon-btn.is-loading > svg { display: none; }

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

@media (prefers-reduced-motion: reduce) {
  .btn.is-loading::before,
  .icon-btn.is-loading::before { animation-duration: 2s; }
}

.btn--primary {
  --btn-bg: var(--red-500);
  --btn-fg: #fff;
  --btn-border: var(--red-500);
}

.btn--primary:hover:not(:disabled) {
  --btn-bg: var(--red-450);
  --btn-border: var(--red-450);
}

.btn--outline {
  --btn-border: var(--line-strong);
}

.btn--outline:hover:not(:disabled) {
  --btn-border: var(--text-2);
  --btn-bg: rgba(255, 255, 255, 0.04);
}

.btn--ghost {
  --btn-fg: var(--text-2);
  min-height: 40px;
  padding: 0 0.875rem;
}

.btn--ghost:hover:not(:disabled) {
  --btn-fg: var(--text);
  --btn-bg: var(--ink-500);
}

.btn--danger {
  --btn-fg: var(--red-300);
  --btn-border: var(--line-strong);
}

.btn--danger:hover:not(:disabled) {
  --btn-bg: var(--red-tint);
  --btn-border: var(--red-500);
}

.btn--sm {
  min-height: 38px;
  padding: 0 0.875rem;
  font-size: var(--step--1);
}

.btn--block { width: 100%; }

.btn svg { flex-shrink: 0; }

.link-underline {
  color: var(--red-300);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--red-tint-2);
  transition: text-decoration-color var(--fast) var(--ease);
}

.link-underline:hover { text-decoration-color: var(--red-300); }

/* --- Moving photo wall -------------------------------------------------------
   Columns drift vertically and loop for ever. Each track holds its frames twice
   and travels exactly half its height, so the seam never shows. Only `transform`
   animates, which the compositor handles on its own thread: no layout, no paint,
   no JavaScript running per frame.
   --------------------------------------------------------------------------- */

.filmwall {
  position: relative;
  height: min(100svh, 1040px);
  min-height: 560px;
  overflow: hidden;
  background: var(--ink-900);
}

.filmwall__cols {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  /* One full-height row, always. Without this the surplus columns wrap onto new
     rows and the wall appears duplicated with a gap in the last cell. */
  grid-template-rows: 100%;
  grid-auto-rows: 0;
  gap: var(--gap);
  align-items: stretch;
  overflow: hidden;
}

/* The markup ships four columns; each breakpoint shows exactly as many as the
   grid has slots for. */
.filmwall__col:nth-child(n + 3) { display: none; }

@media (min-width: 680px) {
  .filmwall__cols { grid-template-columns: repeat(3, 1fr); }
  .filmwall__col:nth-child(3) { display: block; }
}

@media (min-width: 1080px) {
  .filmwall__cols { grid-template-columns: repeat(4, 1fr); }
  .filmwall__col:nth-child(4) { display: block; }
}

.filmwall__col { overflow: hidden; }

.filmwall__track {
  display: block;
  animation: wall-drift var(--dur, 70s) linear infinite;
  will-change: transform;
}

/* Odd columns travel the other way, so the wall drifts instead of marching. */
.filmwall__col:nth-child(even) .filmwall__track { animation-direction: reverse; }

/* Columns start at different points in their loop. A negative delay does this
   without moving the track: shifting it with a margin would push content past
   the end of the loop and open a gap on tall screens. */
.filmwall__col:nth-child(2) .filmwall__track { animation-delay: calc(var(--dur, 70s) * -0.37); }
.filmwall__col:nth-child(3) .filmwall__track { animation-delay: calc(var(--dur, 70s) * -0.13); }
.filmwall__col:nth-child(4) .filmwall__track { animation-delay: calc(var(--dur, 70s) * -0.68); }

.filmwall__frame {
  /* The ratio alone decides the height. A minimum in viewport units would make
     the real column taller than the server calculated, and every column would
     then run at a different speed. */
  aspect-ratio: var(--ar, 1.2);
  margin-bottom: var(--gap);
  overflow: hidden;
  border-radius: var(--r-1);
  background: var(--ink-700);
}

.filmwall__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@keyframes wall-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(0, -50%, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .filmwall__track { animation: none; }
}

.filmwall__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(20, 21, 31, 0.92) 0%, rgba(20, 21, 31, 0.42) 40%, rgba(20, 21, 31, 0.28) 100%),
    radial-gradient(120% 80% at 50% 42%, transparent 45%, rgba(20, 21, 31, 0.5) 100%);
  pointer-events: none;
}

/* --- What is laid over the wall ---------------------------------------------
   The banner itself is .filmwall, above, and it holds these: the line, the two
   buttons and the arrow. They keep the older name because that is what the
   markup calls them. */

.hero__content {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 2;
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
}

.hero__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-5);
}

.hero__line {
  max-width: 24ch;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--text);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: 1.25rem;
  z-index: 2;
  transform: translateX(-50%);
  color: var(--text-3);
  animation: bob 2.4s ease-in-out infinite;
}

/* Keep the call to action clear of the cookie notice on small screens. */
@media (max-width: 700px) {
  .hero__content { padding-bottom: 8.5rem; }
  .hero__scroll { display: none; }
  .hero__actions .btn { flex: 1 1 100%; }
}

@keyframes bob {
  0%, 100% { transform: translate(-50%, 0); }
  50% { transform: translate(-50%, 6px); }
}

/* --- Justified gallery ---------------------------------------------------- */

.gallery {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.gallery__row {
  display: flex;
  gap: var(--gap);
  aspect-ratio: var(--row-ar, 3.4);
  /* Without this a flex item's automatic minimum size beats the row's own
     aspect ratio: a short row holding one upright photograph was drawn at the
     image's intrinsic height — 1343px measured where 251px was meant — and the
     photograph came out wider than the gallery holding it. */
  min-height: 0;
}

/* A last row with too few photographs to fill the width keeps the height of the
   rows above it, set by --row-ar, and simply stops where the photographs end. */
.gallery__row--short {
  justify-content: flex-start;
}

/* A column of a row. Usually one photograph; sometimes two, stacked, which is
   what lets a tall frame stand beside two small ones the way a magazine sets a
   spread (App\Service\Spread). --col-ar is the column's own ratio: for a stack
   that is the series formula, 1 / (1/a + 1/b), because two photographs sharing
   a width add their heights. */
.gallery__col {
  display: flex;
  flex: var(--col-ar, 1.5) 1 0%;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
  min-height: 0;
}

.gallery__row--short .gallery__col {
  flex: 0 0 auto;
  width: auto;
}

/* A tile waiting its turn (app.js, «Gallery: the photographs looked at,
   first») has no picture yet: its words are not drawn in the frame meanwhile. */
.gallery img[data-wait-src] {
  color: transparent;
}

.tile {
  position: relative;
  /* What the flag in the corner is measured against: a mark that is a fixed
     number of pixels is a stamp on a thumbnail and a postage stamp on an open
     photograph. See .pm-rgpd, which is written in cqi — percent of this. */
  container-type: inline-size;
  /* A tile shares its column's HEIGHT with the tile stacked on it, and two
     photographs of one width are as tall as 1/ratio each: so 1/ratio, not the
     ratio. Times 100 so the grow never adds up to less than 1: a lone upright
     photograph at flex-grow 0.67 took 67% of its column and left the rest
     blank («as fotos verticais não estão a ocupar o height todo»). */
  flex: calc(100 / var(--ar, 1.5)) 1 0%;
  width: 100%;
  min-height: 0;
  overflow: hidden;
  background: var(--ink-700);
  border-radius: var(--r-1);
  cursor: zoom-in;
}

.gallery__row--short .gallery__col > .tile {
  flex: 0 0 auto;
  width: auto;
  height: 100%;
  aspect-ratio: var(--ar, 1.5);
}

.tile__open {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  background: none;
  border: 0;
  cursor: zoom-in;
}

.tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--slow) var(--ease), opacity var(--slow) var(--ease);
}

.tile:hover img,
.tile:focus-visible img { transform: scale(1.035); }

/* Autofocus brackets: four corner marks close in on the frame, the way a camera
   confirms focus. Eight small gradients, no extra markup. */
.tile::after {
  --mark: rgba(237, 242, 244, 0.92);

  content: '';
  position: absolute;
  inset: 10px;
  z-index: 2;
  opacity: 0;
  transform: scale(1.035);
  transition: opacity var(--base) var(--ease), transform var(--base) var(--ease);
  pointer-events: none;
  background:
    linear-gradient(var(--mark), var(--mark)) left top / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left top / 2px 16px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right top / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right top / 2px 16px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left bottom / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left bottom / 2px 16px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right bottom / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right bottom / 2px 16px no-repeat;
}

.tile:hover::after,
.tile:focus-within::after {
  opacity: 1;
  transform: none;
}

.tile--video::after { --mark: rgba(239, 35, 60, 0.95); }

/* In the client area the corners hold the tick and the download button, and the
   focus brackets sit at exactly the same inset: the two land on top of each
   other and neither reads. There the frame speaks instead of the brackets. */
.gallery[data-client-gallery] .tile::after { content: none; }

.gallery[data-client-gallery] .tile::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  box-shadow: inset 0 0 0 2px transparent;
  background:
    linear-gradient(to bottom, rgba(20, 21, 31, 0.5) 0%, transparent 34%),
    linear-gradient(to top, rgba(20, 21, 31, 0.55) 0%, transparent 34%);
  opacity: 0;
  transition: opacity var(--base) var(--ease), box-shadow var(--fast) var(--ease);
  pointer-events: none;
}

.gallery[data-client-gallery] .tile:hover::before,
.gallery[data-client-gallery] .tile:focus-within::before { opacity: 1; }

/* Selected: the ring is drawn inside the frame and follows its corners, so it
   never doubles up with a second outline at a different inset. */
.gallery[data-client-gallery] .tile.is-selected::before {
  opacity: 1;
  box-shadow: inset 0 0 0 2px var(--red-500);
}

.tile__meta {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  background: linear-gradient(to top, rgba(20, 21, 31, 0.8), transparent);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--base) var(--ease), transform var(--base) var(--ease);
  pointer-events: none;
}

.tile:hover .tile__meta,
.tile:focus-visible .tile__meta,
.tile.is-selected .tile__meta {
  opacity: 1;
  transform: translateY(0);
}

.tile__tag {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(237, 242, 244, 0.9);
}

/* --- The flag in the corner of a photograph ----------------------------------
   A news caption, folded down to its category flag. On the photograph there is
   only the red block — a few letters a Portuguese parent reads without
   stopping. The words it stands for are one hover away on a mouse, and always
   there in the notice it opens, whose header is the same caption at reading
   size.

   ONE COMPONENT, TWO CAPTIONS. RGPD · Rostos desfocados is a fact about that
   photograph; FAMÍLIA · Só familiares is a fact about the album it is in. They
   share every rule below — the red, the paddings, the hover track, the focus
   ring, the phone step-up — and differ only in their two words and the notice
   they open. Never both on one photograph: the corner is a single slot, and the
   blurred-faces caption wins it (see app/views/partials/gallery.php).
   --------------------------------------------------------------------------- */

/* The top-right autofocus bracket would cross the flag: drop that one corner
   on a tile carrying either caption, keep the other three. */
.tile:has(> .pm-rgpd)::after {
  background:
    linear-gradient(var(--mark), var(--mark)) left top / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left top / 2px 16px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left bottom / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) left bottom / 2px 16px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right bottom / 16px 2px no-repeat,
    linear-gradient(var(--mark), var(--mark)) right bottom / 2px 16px no-repeat;
}

.pm-rgpd {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 5;
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;   /* the caption unfurls leftwards from the corner */
  min-width: 44px;
  min-height: 44px;            /* touch target; the visible flag is much smaller */
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.pm-rgpd__row {
  display: flex;
  align-items: stretch;
  font-family: var(--font-display);
  /* Percent of the photograph, with a floor so it stays readable on a tile in
     a row of four, and a ceiling so it does not become a banner on an open
     frame. */
  font-size: clamp(7px, 2.4cqi, 11px);
  line-height: 1;
  font-weight: 700;
  /* Tight: at this size tracking is what makes the block wide, and width is
     what is seen six times down a gallery. Enough to keep the caps apart, no
     more. */
  letter-spacing: 0.03em;
  text-transform: uppercase;
  font-feature-settings: 'kern' 1;
  white-space: nowrap;
}

/* One block per mark, side by side: a photograph can be both blurred and
   relatives-only, and the corner is one slot. The square is the unit — the
   icon inside it is what changes. */
.pm-rgpd__tag {
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(18px, 8.5cqi, 30px);
  height: clamp(18px, 8.5cqi, 30px);
  /* Not flat --red-500 but a hair of the photograph through it — enough to stop
     it reading as a sticker pasted on top, not enough to soften the drawing
     (white on this stays above 5:1 even over a bright corner). */
  background: rgba(217, 4, 41, 0.93);
  color: #fff;
}

/* A second block is separated by a hairline rather than a gap: a gap would read
   as two flags, and they are one. */
.pm-rgpd__tag + .pm-rgpd__tag {
  box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.35);
}

.pm-rgpd__tag svg {
  display: block;
  width: 62%;
  height: 62%;
  /* Heavier than the site's line icons: at this size a 1.75 stroke goes grey
     against the red. */
  stroke-width: 2.1;
}

/* Collapsed to nothing by default; the track opens and the red block is pushed
   left, exactly reconstituting the caption. */
.pm-rgpd__cap {
  display: grid;
  grid-template-columns: 0fr;
  transition: grid-template-columns var(--base) var(--ease);
}

.pm-rgpd__clip {
  display: flex;
  min-width: 0;
  overflow: hidden;
}

.pm-rgpd__txt {
  display: flex;
  align-items: center;
  /* Vertical centring, not padding: the block beside it is a square with its
     mark in the middle, and two different ways of centring never agree. The
     pixel and a half at the foot is optical: centring the line box leaves caps
     — which have no descenders to fill the space under the baseline — sitting
     low by about that much, measured at 3x. */
  padding: 0 1.05em 0.15em 0.95em;
  background: rgba(20, 21, 31, 0.9);
  color: var(--text);
  font-weight: 600;
  letter-spacing: 0.085em;
}

/* Mouse only. On a phone the red block stays alone — nothing moves under a
   thumb that was trying to open the photograph. */
@media (hover: hover) and (pointer: fine) {
  .pm-rgpd:hover .pm-rgpd__cap { grid-template-columns: 1fr; }
}

.pm-rgpd:focus-visible .pm-rgpd__cap { grid-template-columns: 1fr; }
.pm-rgpd:focus-visible { outline: none; }
.pm-rgpd:focus-visible .pm-rgpd__row { box-shadow: inset 0 0 0 2px #fff; }

/* Client area: every tile there already wears inset controls — the select tick
   at top/left 10px, the download button at bottom/right 10px — so the flag
   takes the same 10px and its top edge runs along the tick's. That also carries
   it clear of the 2px red ring a selected tile draws inside its edge: no sliver
   of photograph trapped between two reds, and no red corner fusing into a blob.
   In the public gallery it stays flush in the corner. */
.tile:has(> .select-toggle) > .pm-rgpd { top: 10px; right: 10px; }

/* The viewer needs no size of its own: the open photograph is the container,
   so the flag is the same fraction of it that it is of a tile. The floor and
   the ceiling in .pm-rgpd__tag are what keep it a mark at both ends. */

@media (prefers-reduced-motion: reduce) {
  .pm-rgpd__cap { transition: none; }
}

/* --- A seleção ---------------------------------------------------------------
   The photographer's edit: the frames he would print.

   A blurred photograph carries a flag in its corner, because the law asks it
   to say so; being chosen asks for nothing of the kind, and a second sticker
   would only compete with the first. So there is nothing added inside the
   frame at all here. A chosen photograph is given about twice the height of the
   contact sheet under it, and one line of type in the margin below: a rule, the
   word, and the photograph's own caption. The size is the mark; the type only
   names what the eye has already been told.
   --------------------------------------------------------------------------- */

.plate-feet {
  display: flex;
  gap: var(--gap);
  margin-bottom: var(--space-5);
}

.plate-feet__item {
  display: flex;
  flex: var(--ar, 1.5) 1 0%;
  align-items: baseline;
  gap: 0.55rem;
  min-width: 0;
  padding-top: 2px;
}

/* A lone upright plate keeps the height of a pair and its own width, so the
   line under it has to be given that width rather than left to spread. */
.plate-feet--short .plate-feet__item {
  flex: 0 0 auto;
  width: calc(100% * var(--ar) / var(--row-ar, 1.25));
}

.plate-feet__rule {
  flex: 0 0 auto;
  align-self: center;
  width: 22px;
  height: 2px;
  background: var(--red-300);
}

.plate-feet__word {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--red-300);
}

.plate-feet__caption {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: var(--step--1);
  color: var(--text-3);
}

/* Air where the edit ends and the rest of the shoot begins. What was left over
   must not read as part of what was chosen out of it. */
.plate-feet + .gallery__row:not(.gallery__row--plate) {
  margin-top: var(--space-4);
}

/* On a telephone the frame is already the whole width, so the caption would
   push the word onto a second line for nothing. */
@media (max-width: 700px) {
  .plate-feet__caption { display: none; }
}

/* The album page: the same red, said quietly, over a thumbnail that is already
   small. Not over a photograph on the site — only in the panel, where the grid
   is a list of files and a mark on one is the point of looking. */
.badge--plate { background: var(--red-tint); color: var(--red-300); }

.album-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.album-actions__note { color: var(--text-3); }
/* --- Video tiles ------------------------------------------------------------ */

.tile__play {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 62px;
  height: 62px;
  padding-left: 4px;
  background: rgba(20, 21, 31, 0.55);
  border: 1px solid rgba(237, 242, 244, 0.55);
  border-radius: 50%;
  color: #fff;
  transform: translate(-50%, -50%);
  backdrop-filter: blur(6px);
  transition: background var(--base) var(--ease), border-color var(--base) var(--ease),
    transform var(--base) var(--ease);
  pointer-events: none;
}

.tile--video:hover .tile__play {
  background: var(--red-500);
  border-color: var(--red-500);
  transform: translate(-50%, -50%) scale(1.06);
}

/* A film sent to an album carries a mark until its poster has been taken.
   Darker than the page behind it — --ink-800 is the page's own colour, and the
   tile read as a hole cut in it — the way the film cards in the panel do. */
.tile__blank {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--ink-900);
  color: var(--text-3);
}

/* How long it runs, in a corner of the tile, the way a player writes it. */
.tile__duration {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 2;
  padding: 0.15rem 0.4rem;
  border-radius: var(--r-1);
  background: rgba(20, 21, 31, 0.78);
  color: rgba(237, 242, 244, 0.92);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

/* In the client area that corner holds the download button. */
.gallery[data-client-gallery] .tile__duration {
  right: auto;
  left: 8px;
}

.filter--video svg { opacity: 0.8; }

.lightbox__stage iframe {
  width: min(1400px, 92vw);
  aspect-ratio: 16 / 9;
  max-height: calc(100svh - 9.5rem);
  border: 0;
  border-radius: var(--r-1);
  background: #000;
}

/* A film of our own. The script fits its box to the stage, so a clip filmed
   with the telephone upright is as tall as the stage allows. */
.lightbox__film {
  display: block;
  max-width: 100%;
  border-radius: var(--r-1);
  background: #000;
}

@media (max-width: 700px) {
  /* The desktop's rows are no use here — four frames in a line are four stamps
     — and one frame per line is a stack, not a gallery: forty photographs
     became forty screens of scrolling. The stream is cut again into lines of
     two wherever two fit (App\Service\PhoneGrid), and the rows dissolve with
     display: contents so their tiles become the gallery's own children while
     keeping their markup, their --row-ar and their place in the order. A plate
     row keeps its line: a plate is meant to be bigger than the rest. */
  .gallery {
    flex-flow: row wrap;
    align-items: flex-start;
  }

  .gallery__row:not(.gallery__row--plate),
  .gallery__row:not(.gallery__row--plate) > .gallery__col {
    display: contents;
  }

  .gallery__row:not(.gallery__row--plate) > .gallery__col > .tile {
    /* The 0.02px keeps a pair whose shares round to 100.001% on one line. */
    flex: none;
    width: calc((100% - var(--ph-gap, 0px)) * var(--ph-w, 1) - 0.02px);
    height: auto;
    aspect-ratio: var(--ar, 1.5);
  }

  .gallery__row--plate {
    flex: 1 0 100%;
  }

  .gallery__row--plate > .gallery__col > .tile {
    height: 100%;
  }
}

/* --- Homepage photostream -------------------------------------------------- */

.stream {
  padding-block: clamp(2rem, 4vw, 3.5rem) clamp(3rem, 6vw, 5rem);
}

.stream__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-5);
  border-bottom: 1px solid var(--line);
}

.stream__all {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  transition: color var(--fast) var(--ease);
}

.stream__all:hover { color: var(--text); }

.stream__foot {
  display: flex;
  justify-content: center;
  margin-top: clamp(2rem, 4vw, 3rem);
}

/* --- Reveal on scroll ----------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* Tiles fade in one after another as their row arrives, left to right. */
.reveal .tile {
  opacity: 0;
  transform: translateY(14px) scale(0.995);
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
  transition-delay: var(--delay, 0ms);
}

.reveal.is-visible .tile {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal .tile { opacity: 1; transform: none; }
}

/* --- Filters & pagination -------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.filter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-2);
  background: transparent;
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease),
    background var(--fast) var(--ease);
}

.filter:hover {
  color: var(--text);
  border-color: var(--line-strong);
}

.filter[aria-current='true'] {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

.filter__count {
  font-size: 0.6875rem;
  opacity: 0.7;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* Room below as well as above: it is the last thing before the footer,
     and sat on it («os botões de números de páginas estão colados ao footer»). */
  margin-block: var(--space-6) clamp(3rem, 6vw, 5rem);
}

.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  height: 42px;
  padding: 0 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  font-size: var(--step--1);
  color: var(--text-2);
}

.pagination a:hover { border-color: var(--line-strong); color: var(--text); }

.pagination [aria-current='page'] {
  background: var(--ink-500);
  border-color: var(--line-strong);
  color: var(--text);
}

/* Marks a skipped run of pages. Plain text, not a pill: there is nothing here
   to click, so it should not look like the buttons either side of it.
   Selector needs the extra class to outrank ".pagination span" above, which a
   bare ".pagination__gap" is not specific enough to override. */
.pagination .pagination__gap {
  min-width: auto;
  height: auto;
  padding: 0;
  border: 0;
  color: var(--text-3);
}

/* --- Lightbox -------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: none;
  /* Solid: the album page showing through behind a photograph was one more
     thing to look at, and on a phone it read as a fault. */
  background: #101119;
}

.lightbox.is-open {
  display: grid;
  grid-template-rows: auto 1fr auto;
  animation: fade-in var(--base) var(--ease);
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Shutter blades part when the viewer opens. */
.lightbox__shutter {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  overflow: hidden;
}

.lightbox__shutter::before,
.lightbox__shutter::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 50.5%;
  background: var(--ink-900);
  transform: translateY(0);
}

.lightbox__shutter::before { top: 0; }
.lightbox__shutter::after { bottom: 0; }

.lightbox.is-open .lightbox__shutter::before {
  animation: blade-up 460ms cubic-bezier(0.16, 0.84, 0.32, 1) both;
}

.lightbox.is-open .lightbox__shutter::after {
  animation: blade-down 460ms cubic-bezier(0.16, 0.84, 0.32, 1) both;
}

@keyframes blade-up {
  from { transform: translateY(0); }
  to { transform: translateY(-101%); }
}

@keyframes blade-down {
  from { transform: translateY(0); }
  to { transform: translateY(101%); }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox__shutter { display: none; }
}

.lightbox__bar {
  position: relative;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) clamp(1rem, 3vw, 2rem);
}

.lightbox__counter {
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  color: var(--text-3);
}

.lightbox__stage {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
  padding-inline: clamp(1rem, 5vw, 4.5rem);
  /* The gestures are ours: sideways is the next picture, not the page. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Script gives this the exact box the photograph fills, so a mark pinned to a
   corner of it is pinned to a corner of the print. It also crops: zooming moves
   the image inside this box rather than over the whole screen. */
.lightbox__frame {
  position: relative;
  container-type: inline-size;
  overflow: hidden;
  border-radius: var(--r-1);
  /* Opacity only. The transform belongs to the drag and the zoom, and a
     keyframe that also animated it would win over them mid-gesture. */
  animation: lift-in var(--base) var(--ease);
  cursor: zoom-in;
  will-change: transform;
}

@keyframes lift-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.lightbox__frame[hidden] { display: none; }

.lightbox.is-zoomed .lightbox__frame { cursor: grab; }
.lightbox.is-zoomed .lightbox__frame:active { cursor: grabbing; }

.lightbox__frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform-origin: 50% 50%;
  will-change: transform;
}

.lightbox__foot {
  min-height: 3.25rem;
  padding: var(--space-3) clamp(1rem, 3vw, 2rem) var(--space-5);
  text-align: center;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* --- Where it is said that faces were blurred ---------------------------------
   On the photograph, and nowhere else.

   Every drawn emblem tried here failed — a shield, a mosaic face, a lab tab, a
   house seal, and later an asterisk, a rule, a dog-ear, a frame, a dot. The
   first four were pictures of nothing in particular; the last five meant
   nothing at all. What holds is the flag in the corner (see .pm-rgpd): a face
   inside a scanner's marks where faces were blurred, a grown-up and a child
   where only a relative may receive the album, the words one hover away and
   the notice one press away.

   There was a line under the stream saying the same thing in the page's own
   voice, and under the photograph in the viewer. Both are gone: the flag says
   it where the thing it is about actually is, and a page that explains itself
   twice before the photographs is a page nobody finishes reading. What a
   screen reader meets is the flag's own label, which carries the same words
   and the way in. */

/* --- The notice it opens ------------------------------------------------------ */

/* The same clothes as the flag: flat blocks, square corners, tracked caps,
   nothing rounded and nothing floating. The caption is hung whole across the
   top at exactly twice the flag's height — the badge that was just pressed,
   read at arm's length — and the glass ground keeps the photograph being
   talked about visible behind what is said about it. `margin: auto` is not
   decoration: without it the dialog comes out pinned near the top. */

.pm-note {
  margin: auto;
  width: min(25rem, calc(100vw - 2rem));
  padding: 0;
  color: var(--text);
  background: rgba(27, 29, 43, 0.55);
  backdrop-filter: blur(22px) saturate(130%);
  -webkit-backdrop-filter: blur(22px) saturate(130%);
  border: 0;
  border-radius: 0;
  outline: 1px solid rgba(255, 255, 255, 0.13);
  box-shadow: none;            /* flat, like the blocks; no floating card */
  overflow: hidden;            /* the caption unrolls inside the panel's edge */
}

/* Opening the notice puts the focus on its heading — the caption itself, which
   is also what labels the dialog — and not on Fechar, so the only red block
   that can be pressed is not already wearing a ring before anyone has touched
   a key. It takes no outline: it is a title, not a control. Tab moves on to
   Fechar, which does show one. */
.pm-note__head:focus,
.pm-note__head:focus-visible { outline: none; }

/* Lighter than a normal modal veil, and blurred rather than blacked out, so
   the picture reads through it. */
.pm-note::backdrop {
  background: rgba(10, 11, 16, 0.5);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/* Where glass is not supported the panel would be a see-through smear, so it
   falls back to something solid. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pm-note { background: rgba(27, 29, 43, 0.97); }
}

/* Opening it repeats the flag's own gesture: the red block is already there —
   it is the thing that was pressed — and the dark half rolls out to the right
   to finish the sentence, exactly as it unfurls under a mouse on the
   photograph. Then the words underneath arrive. No fade-up, no bounce. */
@keyframes pm-note-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pm-note-unroll { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes pm-note-after { from { opacity: 0; } to { opacity: 1; } }

.pm-note[open] { animation: pm-note-in 180ms var(--ease) both; }
.pm-note[open] .pm-note__cap { animation: pm-note-unroll 420ms 90ms var(--ease) both; }
.pm-note[open] .pm-note__body,
.pm-note[open] .pm-note__foot { animation: pm-note-after 260ms 330ms var(--ease) both; }

/* The caption, whole, hung on the top edge and run to both corners. */
.pm-note__head {
  display: flex;
  align-items: stretch;
  margin: 0;
  font-family: var(--font-display);
  font-size: 10.5px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: 0.085em;
  text-transform: uppercase;
}

.pm-note__tag {
  display: flex;
  align-items: center;
  /* 27px tall: the flag on the photograph, doubled exactly. */
  padding: 9px 11px 7.5px 12px;
  background: var(--red-500);
  color: #fff;
}

.pm-note__cap {
  display: flex;
  flex: 1;
  align-items: center;
  padding: 9px 12px 7.5px 11px;
  background: rgba(20, 21, 31, 0.9);
  color: var(--text);
  font-weight: 600;
  letter-spacing: 0.11em;
}

.pm-note__body { padding: var(--space-5) var(--space-5) calc(var(--space-5) - 2px); }

.pm-note__lead {
  margin: 0;
  /* Not --text-2: over a bright photograph seen through glass, the muted grey
     stops clearing the contrast floor. */
  color: rgba(237, 242, 244, 0.93);
  font-size: 0.9375rem;
  line-height: 1.6;
  text-wrap: pretty;
}

/* A second strip closes the panel the way the caption opens it: the small print
   a caption always carries, and the way out, flush in the far corner — the
   diagonal opposite of the red block that opened it. */
.pm-note__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-left: var(--space-5);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.pm-note__meta {
  display: flex;
  align-items: center;
  margin: 0;
  font-family: var(--font-display);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--text-3);
}

.pm-note__close {
  display: inline-flex;
  flex: none;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  /* Red, in the corner opposite the red block that opens the caption: the only
     thing here that can be acted on, and the site paints those red. */
  color: #fff;
  background: var(--red-500);
  border: 0;
  border-radius: 0;
  cursor: pointer;
  transition: background-color var(--fast) var(--ease);
}

.pm-note__close:hover { background: var(--red-600); }

/* The same white inset ring the flag wears when tabbed to — one focus idiom for
   the whole mark, drawn inside so it never crosses the panel's edge. */
.pm-note__close:focus-visible { outline: none; box-shadow: inset 0 0 0 2px #fff; }

@media (prefers-reduced-motion: reduce) {
  .pm-note__close { transition: none; }
  .pm-note[open],
  .pm-note[open] .pm-note__cap,
  .pm-note[open] .pm-note__body,
  .pm-note[open] .pm-note__foot { animation: none; }
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  color: var(--text);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.icon-btn:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: var(--line-strong);
}

.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 6;
}

.lightbox__nav--prev { left: clamp(0.25rem, 1.5vw, 1rem); }
.lightbox__nav--next { right: clamp(0.25rem, 1.5vw, 1rem); }

/* --- Feature band ---------------------------------------------------------- */

.band {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--ink-700);
}

.band__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding-block: clamp(2rem, 4vw, 3rem);
}

.band__title {
  margin: 0;
  font-size: var(--step-3);
  max-width: 20ch;
}

/* --- About ----------------------------------------------------------------- */

.about {
  display: grid;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

@media (min-width: 900px) {
  .about { grid-template-columns: 0.85fr 1fr; }
}

.about__figure {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--r-2);
  background: var(--ink-700);
}

.about__figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about__figure--empty {
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
}

.about__figure--empty img {
  width: 45%;
  height: auto;
  opacity: 0.25;
}

@media (min-width: 900px) {
  .about__figure { position: sticky; top: calc(var(--header-h) + 2rem); }
}

.prose {
  max-width: var(--reading);
  color: var(--text-2);
  font-size: var(--step-1);
  line-height: 1.75;
}

.prose h2 {
  margin-top: 2em;
  color: var(--text);
  font-size: var(--step-2);
}

.prose h2:first-child { margin-top: 0; }

.prose strong { color: var(--text); }

.prose a {
  color: var(--red-300);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.prose ul {
  padding-left: 1.15rem;
  margin: 0 0 1.25em;
}

.prose li { margin-bottom: 0.5em; }

.prose table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 1.5em;
  font-size: var(--step-0);
}

.prose th,
.prose td {
  padding: 0.85rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.prose th {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

.prose code {
  padding: 0.15em 0.4em;
  background: var(--ink-600);
  border-radius: var(--r-1);
  font-size: 0.875em;
  color: var(--text);
}

/* Positioned, so a visually hidden heading inside it (the "Ações" over a row
   of buttons) is held by the box that scrolls. Placed against the page
   instead, it sat past the right edge of a phone and made the whole page
   scroll sideways. */
.table-scroll { position: relative; overflow-x: auto; }

/* --- Forms ----------------------------------------------------------------- */

.field { display: block; margin-bottom: var(--space-5); }

.field__label {
  display: block;
  margin-bottom: 0.5rem;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-2);
}

.field__control {
  width: 100%;
  min-height: 52px;
  padding: 0.85rem 1rem;
  background: var(--ink-700);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text);
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.field__control::placeholder { color: var(--text-3); }

.field__control:hover { border-color: var(--text-3); }

.field__control:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

textarea.field__control {
  min-height: 160px;
  resize: vertical;
  line-height: 1.6;
}

select.field__control {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23A6B0C3' stroke-width='2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2.5rem;
}

.field--invalid .field__control {
  border-color: var(--red-500);
}

.field__error {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--step--1);
  color: var(--red-300);
}

.field__hint {
  display: block;
  margin-top: 0.4rem;
  font-size: var(--step--1);
  color: var(--text-3);
}

.honeypot {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.alert {
  display: flex;
  gap: 0.75rem;
  padding: 1rem 1.15rem;
  margin-bottom: var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--r-2);
  font-size: 0.9375rem;
}

.alert--success {
  background: var(--ok-tint);
  border-color: rgba(87, 176, 138, 0.35);
  color: #8FD3B4;
}

.alert--error {
  background: var(--red-tint);
  border-color: var(--red-tint-2);
  color: var(--red-300);
}

.alert--info {
  background: var(--blue-tint);
  border-color: rgba(110, 155, 255, 0.35);
  color: #A8C2FF;
}

.alert--warn {
  background: var(--warn-tint);
  border-color: rgba(224, 177, 94, 0.35);
  color: var(--warn);
}

/* --- Contact --------------------------------------------------------------- */

.contact {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

@media (min-width: 900px) {
  .contact { grid-template-columns: 0.8fr 1fr; }
}

.contact__card {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.detail-list {
  display: grid;
  gap: var(--space-4);
  margin: var(--space-6) 0 0;
}

.detail-list dt {
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.detail-list dd {
  margin: 0.25rem 0 0;
  color: var(--text);
}

/* --- Footer ---------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  background: var(--ink-900);
}

.site-footer__inner {
  display: grid;
  gap: var(--space-6);
  padding-block: clamp(2.5rem, 5vw, 4rem);
}

@media (min-width: 800px) {
  .site-footer__inner {
    grid-template-columns: 1fr auto;
    align-items: end;
  }
}

.site-footer__cta {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--text);
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-5);
  align-items: center;
}

.site-footer__links a {
  font-size: var(--step--1);
  color: var(--text-3);
  transition: color var(--fast) var(--ease);
}

.site-footer__links a:hover { color: var(--text-2); }

/* The photographer's profiles (partials/social-links): under the footer's
   button, and in the contact page's list. Round, full outline, 44px to press. */
.social-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
}

.detail-list .social-row { margin-top: var(--space-1); }

.social-row__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--text-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease),
    border-color var(--fast) var(--ease);
}

.social-row__link:hover,
.social-row__link:focus-visible {
  color: var(--text);
  background: var(--ink-600);
  border-color: var(--text-3);
}

/* «Redes sociais» on the panel's site page: one line a network, its icon in
   the label. */
.social-links { margin-top: var(--space-6); }

.social-links__form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-4) var(--space-5);
}

.social-links__field .field__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.social-links__actions { grid-column: 1 / -1; }

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  justify-content: space-between;
  padding-block: var(--space-5);
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--text-3);
}

/* --- Cookie notice --------------------------------------------------------- */

.cookie {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 1rem;
  z-index: 90;
  max-width: 620px;
  margin-inline: auto;
  padding: 1.15rem 1.25rem;
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-3);
  transform: translateY(calc(100% + 2rem));
  transition: transform var(--slow) var(--ease);
}

.cookie.is-visible { transform: translateY(0); }

.cookie__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  justify-content: space-between;
}

.cookie p {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text-2);
  flex: 1 1 22ch;
}

.cookie a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }

/* --- Focus layout (login screens) ------------------------------------------ */

.focus-shell {
  display: grid;
  min-height: 100vh;
  grid-template-columns: 1fr;
}

@media (min-width: 1000px) {
  .focus-shell { grid-template-columns: 1.1fr 0.9fr; }
}

.focus-shell__aside {
  display: none;
  position: relative;
  background: var(--ink-900);
}

@media (min-width: 1000px) {
  .focus-shell__aside { display: block; }
}

.focus-shell__aside img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.55;
}

.focus-shell__aside::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(20, 21, 31, 0.2), var(--ink-800));
}

.focus-shell__main {
  display: grid;
  align-content: center;
  gap: var(--space-6);
  padding: clamp(2rem, 6vw, 4rem);
}

.focus-card {
  width: 100%;
  max-width: 420px;
  margin-inline: auto;
}

.focus-card__brand { margin-bottom: var(--space-7); }
.focus-card__brand img { height: 44px; width: auto; }

.focus-card__lead {
  margin: 0 0 var(--space-5);
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.focus-card__foot {
  margin-top: var(--space-5);
  font-size: var(--step--1);
  color: var(--text-3);
}

/* Setting up the authenticator app: three things to do, in order. */
.steps {
  margin: 0 0 var(--space-5);
  padding-left: 1.2rem;
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.steps li { margin-bottom: var(--space-4); }
.steps li:last-child { margin-bottom: 0; }
.steps .tiny { display: block; margin-top: 0.35rem; }

/* The QR code, shown above the key it encodes so scanning it is the first
   thing to try rather than typing the key by hand. */
.qr {
  margin-top: 0.5rem;
  width: 11rem;
  max-width: 100%;
}

.qr svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-1);
  border: 1px solid var(--line);
}

/* The shared secret, spaced so it can be read off the screen and typed. */
.secret {
  display: block;
  margin-top: 0.5rem;
  padding: 0.7rem 0.85rem;
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1rem;
  letter-spacing: 0.14em;
  color: var(--text);
  user-select: all;
}

.secret--wrap {
  font-size: 0.75rem;
  letter-spacing: 0;
  overflow-wrap: anywhere;
}

.disclosure {
  margin-bottom: var(--space-5);
  font-size: var(--step--1);
  color: var(--text-3);
}

.disclosure summary {
  cursor: pointer;
  padding: 0.35rem 0;
}

/* Six digits, spaced out so a mistyped one is easy to see. */
.field__control--code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.5rem;
  letter-spacing: 0.4em;
  text-align: center;
}

/* --- Page heads ------------------------------------------------------------ */

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-5);
  padding-block: clamp(2rem, 5vw, 3.5rem) var(--space-6);
}

.page-head h1 { margin: 0; }

/* Pedir o álbum in one line, between a public album's title and its
   photographs (partials/album-request-bar). The full panel stays below. */
.request-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.request-bar__text {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
  margin: 0;
  color: var(--text-2);
}

.request-bar__text strong { color: var(--text); font-weight: 600; }

.request-bar__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.request-bar__actions form { margin: 0; }

/* «Álbuns públicos» on the client's albums page: one line an album, the name
   opening its page and the ask beside it. */
.ask-list__rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

.ask-list__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding-block: var(--space-3);
  border-top: 1px solid var(--line);
}

.ask-list__row:first-child { border-top: 0; padding-top: 0; }

.ask-list__row form { margin: 0; }

.ask-list__name {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
  min-width: 0;
  color: var(--text);
  text-decoration: none;
}

.ask-list__name:hover strong { text-decoration: underline; text-underline-offset: 3px; }

.ask-list__more { margin: var(--space-3) 0 0; }

/* On a telephone: two equal halves when they fit, one under the other at the
   full width when they do not — never two odd widths stacked. Also the full
   panel under the photographs (partials/album-request), which has less room. */
@media (max-width: 560px) {
  .request-bar { padding: var(--space-4); }
  .request-bar__actions { width: 100%; }
  .request-bar__actions > form,
  .request-bar__actions > .btn { flex: 1 1 9rem; }
  .request-bar__actions .btn { width: 100%; }
}

/* A collection's own page leads with a title and a line about the work, so the
   heading block stacks instead of sitting beside the count. */
.page-head--stacked { align-items: flex-start; }

.page-head--stacked .lead {
  max-width: 52ch;
  margin: var(--space-3) 0 0;
  color: var(--text-2);
  font-size: 1.0625rem;
  line-height: 1.6;
}

/* An icon standing next to a word, on the same line as the word. Left in the
   flow an <svg> sits on the baseline, so the glyph rides above the text it
   belongs to; one flex line puts both on the same centre. */
.inline-icon {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.inline-icon svg { flex-shrink: 0; }

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: var(--space-3);
  color: var(--text-3);
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.back-link svg { flex-shrink: 0; }

.back-link:hover { color: var(--text-1); }

/* Collections index: one card per body of work. */
.collections {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: var(--gap);
}

.collection {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-2);
  background: var(--ink-700);
  color: inherit;
  transition: transform var(--fast) var(--ease);
}

.collection:hover { transform: translateY(-3px); }

.collection__frame {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--ink-600);
}

.collection__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The framing Hugo chose (044): held at a point, brought closer around it. */
  object-position: var(--cover-x, 50%) var(--cover-y, 50%);
  transform-origin: var(--cover-x, 50%) var(--cover-y, 50%);
  transform: scale(var(--cover-zoom, 1));
  transition: transform var(--slow) var(--ease);
}

.collection:hover .collection__frame img { transform: scale(calc(var(--cover-zoom, 1) * 1.04)); }

.collection__body {
  display: block;
  padding: var(--space-4) var(--space-4) var(--space-5);
}

.collection__title {
  display: block;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
}

.collection__summary {
  display: block;
  margin-top: 0.35rem;
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.5;
}

.collection__meta {
  display: block;
  margin-top: var(--space-3);
  color: var(--text-3);
  font-size: 0.8125rem;
}

.cta-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block: var(--space-7) var(--space-6);
  padding: var(--space-5) 0 0;
  border-top: 1px solid var(--line);
}

.cta-band p {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.125rem;
}

/* --- Instagram on an album: a credit, not an advert ---------------------------
   «@handle» with its glyph beside the count of photographs and in the viewer's
   bar, as a photographer's credit reads; then one line and «Seguir» where the
   album ends. The same quiet grey as the words around it, lighter on hover:
   nothing that moves, nothing that comes back. */
.insta-credit {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--text-2);
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--fast) var(--ease);
}

.insta-credit svg { flex: none; }

.insta-credit:hover,
.insta-credit:focus-visible { color: var(--text); }

.insta-credit:hover span { text-decoration: underline; text-underline-offset: 3px; }

.lightbox__where {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--space-4);
  min-width: 0;
}

.lightbox__credit {
  min-height: 44px;
  font-size: var(--step--1);
}

/* The count of photographs and «Seguir @handle» on one line, under the title. */
.album-head__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
}

.album-head__meta .tiny { margin: 0; }

.insta-follow__btn {
  position: relative;
  isolation: isolate;
  gap: 0.5rem;
}

/* As the album opens, once: Instagram's colours run round the button's edge
   and a breath of them lights its ground, then it settles to the plain
   outline. Not again on that page, and not at all for whoever asked for less
   motion. On hover the coloured edge comes back and stays while pointed at. */
.insta-follow__btn::before,
.insta-follow__btn::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  background: linear-gradient(115deg, #feda75, #fa7e1e, #d62976, #962fbf, #4f5bd5, #feda75);
  background-size: 300% 100%;
  opacity: 0;
  pointer-events: none;
}

/* The edge: the gradient shown only in a 1.5px ring. */
.insta-follow__btn::before {
  padding: 1.5px;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  animation: insta-edge 2.6s var(--ease) 0.5s 1 backwards;
  transition: opacity var(--fast) var(--ease);
}

/* The ground: the same colours, faint, under the words. */
.insta-follow__btn::after {
  z-index: -1;
  animation: insta-ground 2.6s var(--ease) 0.5s 1 backwards;
}

.insta-follow__btn:hover::before,
.insta-follow__btn:focus-visible::before {
  opacity: 1;
  animation: none;
}

@keyframes insta-edge {
  0% { opacity: 0; background-position: 0% 50%; }
  18% { opacity: 1; }
  78% { opacity: 1; }
  100% { opacity: 0; background-position: 100% 50%; }
}

@keyframes insta-ground {
  0% { opacity: 0; background-position: 0% 50%; }
  30% { opacity: 0.16; }
  70% { opacity: 0.16; }
  100% { opacity: 0; background-position: 100% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .insta-follow__btn::before,
  .insta-follow__btn::after { animation: none; }
}

@media (pointer: coarse), (max-width: 699px) {
  .insta-follow__btn { min-height: 44px; }
}

.page-head__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* Top left, clear of the mark a blurred photograph carries top right: over it,
   the tick hid the word and took the taps meant for the notice. */
.select-toggle {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: rgba(20, 21, 31, 0.65);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: var(--r-full);
  color: transparent;
  cursor: pointer;
  opacity: 0;
  backdrop-filter: blur(6px);
  transition: opacity var(--fast) var(--ease), background var(--fast) var(--ease),
    border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.tile:hover .select-toggle,
.tile:focus-within .select-toggle,
.select-toggle:focus-visible,
.tile.is-selected .select-toggle { opacity: 1; }

.tile.is-selected .select-toggle {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

/* The download button sits on a photograph, so it carries its own dark ground.
   The default icon button is nearly transparent and disappears on pale frames. */
.tile__action {
  position: absolute;
  bottom: 10px;
  right: 10px;
  z-index: 4;
  width: 34px;
  height: 34px;
  background: rgba(20, 21, 31, 0.65);
  border-color: rgba(255, 255, 255, 0.35);
  color: #fff;
  opacity: 0;
  transform: translateY(4px);
  backdrop-filter: blur(6px);
  transition: opacity var(--base) var(--ease), transform var(--base) var(--ease),
    background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.tile__action:hover {
  background: var(--red-500);
  border-color: var(--red-500);
}

.tile:hover .tile__action,
.tile:focus-within .tile__action {
  opacity: 1;
  transform: none;
}

/* A touch screen has no hover, so both stayed invisible there: nothing said a
   photograph could be ticked or saved on its own, though the page asks for
   exactly that. There they are always shown, and at a thumb's size. */
@media (hover: none) {
  .tile .select-toggle,
  .tile__action {
    width: 44px;
    height: 44px;
    opacity: 1;
    transform: none;
  }
}

.selection-bar {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  z-index: 95;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: 0.75rem 0.85rem 0.75rem 1.25rem;
  background: var(--ink-500);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  box-shadow: var(--shadow-3);
  transform: translate(-50%, calc(100% + 2rem));
  transition: transform var(--base) var(--ease);
}

.selection-bar.is-visible { transform: translate(-50%, 0); }

.selection-bar__count {
  font-size: var(--step--1);
  color: var(--text-2);
  white-space: nowrap;
}

.empty-state {
  display: grid;
  place-items: center;
  gap: var(--space-4);
  padding: clamp(3rem, 10vw, 6rem) var(--space-5);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-3);
  text-align: center;
  color: var(--text-3);
}

.empty-state h2 {
  margin: 0;
  font-size: var(--step-2);
  color: var(--text-2);
}

/* --- Admin ----------------------------------------------------------------- */

.admin {
  display: grid;
  min-height: 100vh;
  grid-template-columns: 1fr;
}

@media (min-width: 1000px) {
  .admin { grid-template-columns: 248px 1fr; }
}

.admin__side {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  padding: var(--space-4) var(--space-5);
  background: var(--ink-900);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}

@media (min-width: 1000px) {
  .admin__side {
    position: sticky;
    top: 0;
    height: 100vh;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    padding: var(--space-6) var(--space-4);
    border-right: 1px solid var(--line);
    border-bottom: 0;
    overflow: visible;
  }
}

.admin__brand {
  display: none;
  margin-bottom: var(--space-6);
  padding-inline: var(--space-3);
}

.admin__brand img { height: 30px; width: auto; }

@media (min-width: 1000px) {
  .admin__brand { display: block; }
}

.admin__nav {
  display: flex;
  gap: var(--space-2);
}

@media (min-width: 1000px) {
  .admin__nav { flex-direction: column; }
}

.admin__link {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.7rem 0.85rem;
  border-radius: var(--r-2);
  font-size: 0.9375rem;
  color: var(--text-2);
  white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.admin__link:hover {
  background: var(--ink-600);
  color: var(--text);
}

.admin__link[aria-current='page'] {
  background: var(--red-tint);
  color: var(--red-300);
}

.admin__link--button {
  width: 100%;
  background: none;
  border: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.admin__link svg { flex-shrink: 0; opacity: 0.85; }

.admin__foot {
  margin-top: auto;
  display: flex;
  gap: var(--space-2);
}

@media (min-width: 1000px) {
  .admin__foot { flex-direction: column; }
}

/* --- The panel on a phone ----------------------------------------------------
   The navigation used to be a row of seven labelled links in a bar that scrolled
   sideways, which is how the horizontal scrollbar got there: they do not fit and
   `overflow-x: auto` let them not fit. Below a thousand pixels the sections
   become a fixed bar along the bottom — where a thumb is — and the top bar keeps
   the brand, the link to the site and the way out. Signing out has to stay
   reachable, so it does not move into the tab bar. */

@media (max-width: 999px) {
  /* The top bar at its own height and the page below taking the rest. With
     both rows left to size themselves, a page shorter than the screen — a
     tab with one request on it, an empty list — shared the spare height
     between them, and the bar grew to half the phone with the logo floating
     in the middle of it. */
  .admin { grid-template-rows: auto 1fr; }

  /* The bar never makes the page wider than the screen: left to its
     min-content, the client's picture and labelled links pushed every page of
     the panel 22px past a 360px phone. The side padding is the page's own, so
     the mark lines up with the content under it, and the bar is no taller than
     its 44px targets need. */
  .admin__side {
    min-width: 0;
    overflow: visible;
    justify-content: space-between;
    padding: var(--space-2) clamp(1rem, 3vw, 2.5rem);
  }

  /* An image with max-width: 100% may shrink to nothing in a flex row, and the
     mark was the first thing to give. */
  .admin__brand {
    display: block;
    flex-shrink: 0;
    margin: 0;
    padding-inline: 0;
  }

  /* Thumb-sized targets up here, labels and all. */
  .admin__foot .admin__link {
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
  }

  /* The tabs share the width of the screen, however long the words are in the
     language being read. A plain 1fr column will not shrink below its word, so
     in Spanish the ninth tab was pushed off a 360px phone and in every language
     the labels ran into each other. With a zero minimum the columns always fit,
     and the ellipsis already on the label is only the last resort. */
  .admin__nav {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 90;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 0;
    background: var(--ink-900);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }

  .admin__nav .admin__link {
    min-width: 0;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    min-height: 56px;
    padding: 6px 2px;
    border-radius: 0;
    font-size: 0.625rem;
    text-align: center;
  }

  .admin__nav .admin__link span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .admin__nav .admin__link[aria-current='page'] {
    background: var(--ink-700);
    color: var(--text);
  }

  /* Room for the bar, and for the selection bar to sit above it. */
  .admin__main { padding-bottom: calc(56px + env(safe-area-inset-bottom, 0) + var(--space-6)); }

  /* Lifted this far, the selection bar has further to go when it hides as
     well: with only the 2rem it had, its top edge stayed on screen across the
     tabs with nothing selected. The bulk bar's lift is said after its own
     rule, which comes later in the file and won over the one that was here. */
  .selection-bar {
    bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3));
    transform: translate(-50%, calc(100% + 56px + env(safe-area-inset-bottom, 0px) + 2rem));
  }

  /* Lifted above the tab bar, the selection bar covered the end of the list:
     the page still ended just the tab bar's height below the last photograph,
     so the bar hid its lower edge and its download button however far one
     scrolled. While the bar is showing, the page ends clear of it. */
  .admin__main:has(.selection-bar.is-visible) {
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3) + 4rem + var(--space-6));
  }

  .toolbar__search { flex: 1 1 100%; }
  .toolbar__search input { width: 100%; max-width: none; }

  /* Answering is what a request card is for: laid out for touch, its buttons
     get a thumb's height. */
  .booking__actions .btn { min-height: 44px; }
}

/* A single pill 650px long cannot sit on a phone: the count and the download
   button went off both sides. Here it becomes a card across the width, the
   count and "Limpar" on one row and the two actions sharing the next. */
@media (max-width: 700px) {
  .selection-bar {
    left: var(--space-3);
    right: var(--space-3);
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
    border-radius: var(--r-4);
    transform: translateY(calc(100% + 56px + env(safe-area-inset-bottom, 0px) + 2rem));
  }

  .selection-bar.is-visible { transform: none; }

  /* Here the bar is a card of two rows, and the page's end makes room for it. */
  .admin__main:has(.selection-bar.is-visible) {
    padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3) + 7.5rem + var(--space-6));
  }

  /* Half the row, so nothing but "Limpar" can join it. */
  .selection-bar__count { flex: 1 0 50%; }

  .selection-bar .btn { min-height: 44px; }

  .selection-bar .btn--outline,
  .selection-bar .btn--primary {
    flex: 1 1 calc(50% - var(--space-1));
    padding-inline: var(--space-3);
    white-space: normal;
    line-height: 1.2;
    text-align: center;
  }
}

@media (max-width: 560px) {
  /* On a phone the tabs are sized by their words instead of split evenly:
     "Site" needs a third of what "Fotografias" does, and giving each only what
     it needs is what leaves a gap between one word and the next. The type
     comes down a pixel on the narrowest screens, where the Spanish labels are
     still a little too wide at full size. */
  .admin__nav { grid-auto-columns: minmax(0, auto); }

  .admin__nav .admin__link { font-size: clamp(0.5625rem, 2.5vw, 0.625rem); }

  /* In Portuguese the words leave a little over, and the shortest tab gets its
     part: none narrower than 2rem, what remains still shared evenly, so the
     space between one word and the next stays the same along the bar. Sized
     by its word alone, "Site" was 25px across at 390. Spanish has nothing
     over on a phone, its words alone fill the bar, and English only a few
     pixels, so there the tabs keep to their words. */
  .admin__nav:lang(pt) { grid-auto-columns: minmax(var(--space-6), auto); }

  /* The client's picture in the top bar already opens the account, so its tab
     gives up its place in a bar of eight, and the picture shows where you are
     instead. */
  .admin__nav .admin__link--account { display: none; }

  .admin__who--link[aria-current='page'] .avatar {
    border-color: var(--red-400);
    box-shadow: 0 0 0 2px var(--red-tint-2);
  }

  /* With the picture in the bar as well, the labelled pair no longer fits
     beside the mark: at 360px it pushed the bar 22px wider than the screen,
     and in English it did so at 390. The house goes quiet — the mark beside it
     leads to the same place — and signing out keeps its word. Clipped rather
     than removed, so a screen reader still reads it. */
  .admin__who--link ~ .admin__foot > .admin__link span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}

/* Only on the narrowest phones do the two labels stop fitting beside the mark.
   Measured at 375px: the mark is 40px and the labelled pair 241px, which clears
   the bar with room to spare — so keep the words. They are what says which of
   the two glyphs leaves the panel and which one signs out. Under 340px they are
   clipped rather than removed, so a screen reader still reads them. */
@media (max-width: 339px) {
  .admin__foot .admin__link span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}

.admin__main {
  min-width: 0;
  padding: clamp(1.5rem, 3vw, 2.5rem) clamp(1rem, 3vw, 2.5rem) var(--space-9);
}

.admin__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

.admin__head h1 {
  margin: 0;
  font-size: var(--step-3);
}

/* The line under a page title that says what the page is for. Its margin was
   zeroed inline, so it sat on the title's descenders. */
.admin__lead { margin: var(--space-2) 0 0; }

/* The page head, the same on every page of both panels: less air around it on
   a phone, so the first card starts in the top fifth of the screen, and the
   one button it carries at a thumb's size. */
@media (max-width: 700px) {
  .admin__main { padding-top: var(--space-4); }

  .admin__head {
    gap: var(--space-3);
    margin-bottom: var(--space-5);
  }

  .admin__head .btn--sm { min-height: 44px; }
}

.panel {
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  margin-bottom: var(--space-5);
}

.panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.panel__head h2 {
  margin: 0;
  font-size: var(--step-1);
}

/* --- The censorship of one photograph, inside its own sheet ------------------
   One photograph, two files: the one the club downloads and the one the site
   publishes. Side by side, because "is this the right face blurred" is a
   question you answer by looking at both at once. */

/* A border of its own, transparent at rest, so turning the warning on does not
   move everything under it by two pixels.

   Qualified with .sheet__group because that rule comes later in the file and
   resets padding and border: at equal specificity it won, and none of this
   ever applied. The negative inline margin keeps the text in line with the
   groups above and below, and lets only the box reach outward. */
.sheet__group.censor {
  margin-inline: calc(-1 * (var(--space-3) + 1px));
  padding: var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--r-2);
}

.censor__line {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.5;
}

/* Marked for the public side and nobody has looked at it yet. Amber, and the
   whole fieldset carries it, so it is not something to be scrolled past. */
.censor.is-alarm {
  border: 1px solid rgba(224, 177, 94, 0.45);
  background: rgba(224, 177, 94, 0.08);
}

.censor.is-alarm .censor__line { color: var(--warn); }

.censor__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

/* display: grid above beats the browser's own [hidden] rule, so hiding the
   comparison needs saying here. Without this the pair showed on photographs
   with nothing censored — and its left-hand frame is the uncensored original. */
.censor__pair[hidden] { display: none; }

.censor__side {
  display: grid;
  gap: 0.4rem;
  margin: 0;
}

.censor__side img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--r-2);
  background: var(--ink-900);
  border: 1px solid var(--line);
}

.censor__side figcaption {
  color: var(--text-3);
  font-size: 0.6875rem;
  line-height: 1.3;
}

.censor__go { justify-self: start; }

/* --- Space on the server -------------------------------------------------------
   One bar against the plan's quota. Green, then amber from four fifths, red from
   nineteen twentieths — late enough not to cry wolf, early enough that there is
   still room to choose what to archive. */

.gauge {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.gauge__figures {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0;
}

.gauge__figures strong {
  font-family: var(--font-display);
  font-size: var(--step-2);
}

.gauge__bar {
  position: relative;
  height: 10px;
  overflow: hidden;
  border-radius: var(--r-full);
  background: var(--ink-900);
  border: 1px solid var(--line);
}

.gauge__fill {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: inherit;
  background: var(--ok);
  transition: width var(--base) var(--ease);
}

.gauge--warn .gauge__fill { background: var(--warn); }
.gauge--danger .gauge__fill { background: var(--red-400); }

/* Under the bar while only the originals are counted, or a measurement of the
   rest stopped halfway: said quietly, it is a fact about the figure, not an
   alarm. */
.gauge__note {
  margin: var(--space-3) 0 0;
  color: var(--text-3);
  font-size: var(--step--1);
  line-height: 1.5;
}

/* --- When the site cannot answer, and «Avisos» ---------------------------------
   The page a visitor gets while the database is away (pages/unavailable, and
   public/maintenance.html, which uses these same classes because it can use
   nothing else), and the strip at the top of every page of the panel. Calm on
   purpose: nothing on the first is the visitor's to fix, and the second is
   read, not obeyed — the same thin rule as .admin-reminder, one per line, in
   the colour of how much it matters. */

.unavailable {
  max-width: 42rem;
  text-align: center;
}

.unavailable__lead { margin-inline: auto; }

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

.unavailable__contact {
  margin: var(--space-6) 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.unavailable__other {
  margin: var(--space-2) 0 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

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

.attention__heading {
  margin: 0 0 var(--space-2);
  color: var(--text-3);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.attention__list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.attention__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.5;
}

/* How loud a line is shows in its whole border and its ground, never in a
   rule down one side. */
.attention__item--warn {
  border-color: rgba(224, 177, 94, 0.45);
  background: var(--warn-tint);
}

.attention__item--error {
  border-color: var(--red-tint-2);
  background: var(--red-tint);
  color: var(--text);
}

/* The sentence takes the line; a button, when there is one, sits at its end
   on a wide screen and wraps under it on a phone. */
.attention__text {
  flex: 1 1 18rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.attention__action { margin: 0; }

/* A whole panel that is one link: the gauge on the overview opens the page
   that answers it. */
.panel--link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--fast) var(--ease);
}

.panel--link:hover { border-color: var(--line-strong); }

.table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

tr.is-archived td { color: var(--text-3); }

/* An archived photograph keeps only its smallest copy. Greyed, so it reads at
   a glance as a record rather than as work that is still live. */
.photo-card.is-archived img,
.order-item--archived img {
  filter: grayscale(1);
  opacity: 0.55;
}

.order-item--archived { position: relative; }

.archive-tools {
  display: grid;
  gap: var(--space-4);
}

.archive-tools > p { margin: 0; }

.archive-tools form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
}

.archive-tools__title {
  margin: var(--space-3) 0 0;
  font-size: var(--step-0);
}

/* The sheet of an archived photograph: take its file back. */
.sheet__restore {
  display: grid;
  gap: var(--space-3);
  margin: 0 var(--space-4) var(--space-4);
  padding: var(--space-4);
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.sheet__restore p { margin: 0; }

/* Both of these set display, which beats the browser's own [hidden] rule; so
   hiding them has to be said here, or the restore form sits on every sheet and
   the censorship section on an archived one. */
.sheet__restore[hidden],
.sheet__group[hidden] { display: none; }

/* The lightbox's own tools, right of the counter: the high-quality view, when
   there is one, then the cross. */
.lightbox__tools {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.lightbox__hq[hidden] { display: none; }

/* The one thing a family can do with a photograph here besides look, so it is
   the page's primary button, not a grey word beside the cross («bem cinzento
   não fica bem evidente, então o cliente não vai ver»). Once on, it steps
   back: an outline in the colour that means done. */
.lightbox__hq[aria-pressed='true'] {
  --btn-bg: transparent;
  --btn-fg: var(--ok);
  --btn-border: var(--ok);
}

/* --- Site pictures -----------------------------------------------------------
   One panel per spot. The preview is held to the shape the page it feeds
   actually shows, so what is framed here is what will be framed there — a
   portrait dropped into the sign-in picture should look wrong on this screen
   rather than on the sign-in screen. */

.site-spots {
  display: grid;
  gap: var(--space-5);
  align-items: start;
}

@media (min-width: 900px) {
  .site-spots { grid-template-columns: repeat(2, 1fr); }
}

.site-spot {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-bottom: 0;
}

.site-spot .panel__head { margin-bottom: 0; }
.site-spot__hint { margin: 0; }

.site-spot__preview {
  display: grid;
  place-items: center;
  width: 100%;
  margin-inline: auto;
  overflow: hidden;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

/* Each preview holds the shape and the crop of the page it feeds: 4:5 is what
   the figure on About is, and the column beside the sign-in form is taller
   still. Capped in width so a panel does not turn into a wall. */
.site-spot__preview--portrait {
  aspect-ratio: 4 / 5;
  max-width: 320px;
}

.site-spot__preview--aside {
  aspect-ratio: 2 / 3;
  max-width: 268px;
}

.site-spot__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.site-spot__empty {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* An empty spot has nothing to frame yet, so on a phone its placeholder keeps
   the shape but not the size: at full width it was a dark wall the height of
   the screen, and the field and the button that fill it fell below it. At
   that size its line of text has no room to spare, so it keeps clear of the
   frame and wraps, centred, when the language runs long. */
@media (max-width: 700px) {
  .site-spot__preview:has(.site-spot__empty) { max-width: 12rem; }

  .site-spot__empty {
    padding-inline: var(--space-3);
    text-align: center;
  }
}

.site-spot__file {
  margin: 0;
  color: var(--text-3);
  word-break: break-all;
}

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}

.stat {
  padding: var(--space-5);
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.stat__value {
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
}

.stat__label {
  margin-top: 0.5rem;
  font-size: var(--step--1);
  color: var(--text-3);
}

/* An address has no spaces to break at, so a long one ran out of its card. */
.stat__value--small { font-size: 1.05rem; line-height: 1.5; overflow-wrap: anywhere; }
.stat__unit { font-size: 0.9rem; color: var(--text-3); font-weight: 400; }

.admin__who {
  display: none;
  margin: 0 0 var(--space-5);
  padding: 0 var(--space-3);
  line-height: 1.35;
}

.admin__who .tiny { display: block; }
.admin__who strong { font-family: var(--font-display); font-size: 0.95rem; }

@media (min-width: 1000px) {
  .admin__who { display: block; }
}

/* --- The client's own corner: picture, bell, notices ------------------------ */

.avatar {
  flex-shrink: 0;
  width: var(--avatar, 40px);
  height: var(--avatar, 40px);
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: var(--ink-600);
  object-fit: cover;
}

.avatar--initials {
  display: inline-grid;
  place-items: center;
  background: linear-gradient(135deg, var(--ink-500), var(--ink-700));
  color: var(--text);
  font-family: var(--font-display);
  font-size: calc(var(--avatar, 40px) * 0.38);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* The picture heads the panel: beside the name on a wide screen, alone in the
   top bar on a phone. */
.admin__who--link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  border-radius: var(--r-2);
  color: inherit;
  text-decoration: none;
}

.admin__who--link:hover strong,
.admin__who--link:focus-visible strong {
  color: var(--red-300);
}

@media (min-width: 1000px) {
  .admin__who--link { display: flex; }
}

@media (max-width: 999px) {
  .admin__who--link > span:not(.avatar) { display: none; }

  /* In the top bar the picture joins the two links on the right, level with
     them. It kept the sidebar's margin and padding up here, which lifted it
     above the links, made the bar 20px taller than anything in it, and left it
     floating halfway across on a tablet. After .admin__who, which weighs the
     same and would otherwise win. */
  .admin__who--link {
    margin: 0 0 0 auto;
    padding: 0;
  }
}

.admin__nav .admin__link { position: relative; }

.nav-badge {
  min-width: 1.25rem;
  height: 1.25rem;
  margin-left: auto;
  padding: 0 0.35rem;
  border-radius: var(--r-full);
  background: var(--red-500);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.25rem;
  text-align: center;
}

@media (max-width: 999px) {
  .admin__nav .admin__link .nav-badge {
    position: absolute;
    top: 6px;
    left: calc(50% + 4px);
    min-width: 1rem;
    max-width: none;
    height: 1rem;
    margin: 0;
    padding: 0 0.25rem;
    font-size: 0.625rem;
    line-height: 1rem;
  }
}

.news-banner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: var(--space-5);
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--red-tint-2);
  border-radius: var(--r-2);
  background: var(--red-tint);
  color: var(--text);
  text-decoration: none;
  transition: border-color var(--fast) var(--ease);
}

.news-banner svg:first-child { color: var(--red-300); }
.news-banner svg:last-child { margin-left: auto; opacity: 0.7; }
.news-banner:hover { border-color: var(--red-400); }

.news {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.news__link {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
  color: var(--text-2);
  text-decoration: none;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.news__link:hover { border-color: var(--line-strong); color: var(--text); }

.news__item.is-new .news__link {
  border-color: var(--red-tint-2);
  color: var(--text);
}

.news__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--ink-600);
  color: var(--text-2);
}

.news__item.is-new .news__icon { color: var(--red-300); }

.news__body { display: grid; gap: 0.15rem; min-width: 0; }
.news__time { color: var(--text-3); }

.news__new {
  margin-left: auto;
  padding: 0.15rem 0.55rem;
  border-radius: var(--r-full);
  background: var(--red-500);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* --- A conversation ------------------------------------------------------------
   A family's thread with the photographer, and the same thread in his inbox,
   drawn the way a conversation on a phone is drawn. WhatsApp was Hugo's
   direction, not a model to copy: the other side's bubbles on the left, your
   own on the right in the site's red, the time tucked into the bubble's
   corner, a pill where each day starts, one bar at the bottom with a round
   button to send — and no tails, no wallpaper, no ticks. Whether the other
   side has read you is one word under your last message.

   The whole thing is one box of a fixed height: the log scrolls inside it and
   the bar stays in reach, on a phone as on a laptop. Every body keeps its line
   breaks and may break anywhere, so a pasted address cannot push the page wider
   than a 360px phone. */

.chat {
  --chat-mine: #58152A;
  --chat-theirs: var(--ink-700);
  display: flex;
  flex-direction: column;
  max-width: 52rem;
  height: clamp(24rem, calc(100dvh - 15rem), 46rem);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
  background: var(--ink-900);
}

.chat__intro {
  max-width: 40rem;
  margin: var(--space-2) 0 0;
}

.chat__viewport {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}

.chat__log {
  display: flex;
  flex-direction: column;
  gap: 2px;
  height: 100%;
  margin: 0;
  padding: var(--space-4) clamp(0.75rem, 4%, 2rem) var(--space-3);
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
  background: var(--ink-900);
}

.chat__empty {
  margin: auto;
  text-align: center;
}

.chat__empty span,
.chat__day span {
  display: inline-block;
  padding: 0.3rem 0.75rem;
  border-radius: var(--r-3);
  background: var(--ink-700);
  color: var(--text-2);
  font-size: 0.75rem;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}

.chat__day {
  margin: var(--space-3) 0 var(--space-2);
  text-align: center;
}

.chat__msg {
  display: flex;
  justify-content: flex-start;
}

.chat__msg--mine { justify-content: flex-end; }

/* A run from one side starts a little apart from the other side's. */
.chat__msg--first:not(:first-child) { margin-top: var(--space-2); }

.chat__bubble {
  position: relative;
  max-width: min(34rem, 82%);
  padding: 0.4rem 0.6rem 0.45rem 0.65rem;
  border-radius: var(--r-4);
  background: var(--chat-theirs);
  color: var(--text);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
}

.chat__msg--mine .chat__bubble { background: var(--chat-mine); }

/* Which side is talking is said by the side the bubble sits on and by one
   tighter corner, the one nearest the speaker, on the first bubble of a run. */
.chat__msg--first .chat__bubble { border-top-left-radius: var(--r-1); }
.chat__msg--first.chat__msg--mine .chat__bubble {
  border-top-left-radius: var(--r-4);
  border-top-right-radius: var(--r-1);
}

.chat__body {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.4;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Room at the end of the last line for the time, which sits in the corner: a
   short message stays on one line with it, a long one flows around it. */
.chat__body::after {
  content: '';
  display: inline-block;
  width: 3rem;
}

.chat__meta {
  position: absolute;
  right: 0.55rem;
  bottom: 0.3rem;
  display: flex;
  align-items: center;
  gap: 0.2rem;
  margin: 0;
  color: rgba(237, 242, 244, 0.6);
  font-size: 0.6875rem;
  line-height: 1;
  white-space: nowrap;
}

/* «A enviar…», «Enviada», «Lida»: one quiet line under your last message. */
.chat__status {
  align-self: flex-end;
  margin: 0.2rem 0.15rem 0;
  color: var(--text-3);
  font-size: 0.6875rem;
}

.chat__status.is-read { color: var(--text-2); }
.chat__status[hidden] { display: none; }

/* Sent from this page and not yet answered by the server. */
.chat__msg--pending .chat__bubble { opacity: 0.8; }

/* New messages arrived while the reader was further up: a round button in
   the corner takes them down, with how many. */
.chat__jump {
  position: absolute;
  right: 0.9rem;
  bottom: 0.9rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border: 0;
  border-radius: var(--r-full);
  background: var(--ink-600);
  color: var(--text);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
  cursor: pointer;
}

.chat__jump[hidden] { display: none; }

.chat__jump-count {
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  min-width: 1.25rem;
  padding: 0.1rem 0.3rem;
  border-radius: var(--r-full);
  background: var(--red-500);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.1;
}

.chat__form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem;
  margin: 0;
  padding: 0.5rem 0.6rem;
  border-top: 1px solid var(--line);
  background: var(--ink-800);
}

.chat__input {
  flex: 1 1 0;
  min-width: 0;
  min-height: 2.75rem;
  max-height: 9rem;
  padding: 0.7rem 1rem;
  border: 1px solid transparent;
  border-radius: 1.375rem;
  background: var(--ink-700);
  color: var(--text);
  font: inherit;
  font-size: 0.9375rem;
  line-height: 1.35;
  resize: none;
  overflow-y: auto;
}

.chat__input::placeholder { color: var(--text-3); }

.chat__input:focus-visible {
  outline: none;
  border-color: var(--line-strong);
}

.chat__send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: var(--r-full);
  background: var(--red-500);
  color: #fff;
  cursor: pointer;
  transition: background-color 150ms ease;
}

.chat__send:hover { background: var(--red-600); }
.chat__send:focus-visible { outline: 2px solid var(--red-300); outline-offset: 2px; }
.chat__send:disabled { opacity: 0.6; cursor: default; }
.chat__send svg { margin-left: -2px; }

.chat__error {
  flex: 1 0 100%;
  margin: 0 0.4rem;
  color: var(--red-300);
  font-size: var(--step--1);
}

@media (max-width: 560px) {
  .chat {
    height: calc(100dvh - 12rem);
    min-height: 20rem;
  }

  .chat__bubble { max-width: 88%; }
}

/* --- The photographer's inbox ------------------------------------------------- */

.inbox__list .news__body { flex: 1 1 auto; }

.inbox__who {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
}

.inbox__who strong {
  overflow: hidden;
  color: var(--text);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inbox__who time { flex-shrink: 0; }

.inbox__last {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A count here, not the word "Novo": how many are waiting is the news. */
.inbox__list .news__new {
  min-width: 1.6rem;
  margin-left: 0;
  letter-spacing: 0;
  text-align: center;
}

.inbox__news {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
  margin: 0 0 var(--space-4);
  padding: 0.7rem 1rem;
  border: 1px solid var(--red-tint-2);
  border-radius: var(--r-2);
  color: var(--text);
}

.inbox__search {
  max-width: 30rem;
  margin-bottom: var(--space-5);
}

.inbox__search-row {
  display: flex;
  gap: var(--space-2);
}

.inbox__search-row .field__control {
  flex: 1 1 auto;
  min-width: 0;
}

/* The overview's reminder while the inbox has no access of its own: a quiet
   grey note, since it is a thing to do, not a fault. */
.admin-reminder {
  margin: 0 0 var(--space-5);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.5;
}

/* Two words that are one thing to press: not split across lines on a phone. */
.admin-reminder a { white-space: nowrap; }

.inbox-access__intro {
  max-width: 40rem;
  margin: 0 0 var(--space-5);
  color: var(--text-2);
}

.inbox-access__form {
  max-width: 28rem;
  margin-top: var(--space-4);
}

.inbox-access__status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
}

.inbox-access__revoke {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

/* The inbox has one place, so on a phone it has no bar along the bottom: the
   top bar holds the mark, the way back to the list with its count, and the way
   out. The page no longer needs the room the bar would take. */
@media (max-width: 999px) {
  .admin--inbox .admin__main { padding-bottom: var(--space-9); }

  .admin--inbox .inbox__home { margin-left: auto; }

  .admin--inbox .inbox__home .nav-badge { margin-left: 0.25rem; }
}

/* In the panel's top bar on a phone, «Mensagens» joined the way to the site
   and the way out, and at 360px in Spanish the three with their words pushed
   «Salir» off the screen. The messages link keeps its glyph and its count;
   its word is clipped rather than removed, so a screen reader still says it. */
@media (max-width: 560px) {
  .admin__foot .admin__link--inbox > span:not(.nav-badge):not(.sr-only) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* The count sits on the glyph, as on the tabs below, so the link is no
     wider than its 44px target. */
  .admin__foot .admin__link--inbox {
    position: relative;
    padding-inline: 0.5rem;
  }

  .admin__foot .admin__link--inbox .nav-badge {
    position: absolute;
    top: 4px;
    left: calc(50% + 2px);
    min-width: 1rem;
    height: 1rem;
    margin: 0;
    padding: 0 0.25rem;
    font-size: 0.625rem;
    line-height: 1rem;
  }

  /* And the three sit a little closer, which is what lets «Salir» stay whole. */
  .admin__foot:has(.admin__link--inbox) { gap: 0; }

  .admin__foot:has(.admin__link--inbox) .admin__link:not(.admin__link--inbox) { padding-inline: 0.6rem; }
}


/* The account page: the picture beside the details. */
.profile {
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 700px) {
  .profile { grid-template-columns: 180px minmax(0, 1fr); align-items: start; }
}

.profile__picture {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
}

.profile__choose { cursor: pointer; }
.profile__choose:focus-within { outline: 2px solid var(--red-400); outline-offset: 2px; }
.profile__choose.is-busy { opacity: 0.6; pointer-events: none; }
.profile__hint,
.profile__note { margin: 0; }

.profile__details { display: grid; gap: var(--space-4); }
.profile__details .detail-list { margin: 0; }

.link-button {
  padding: 0;
  background: none;
  border: 0;
  color: var(--red-300);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

.link-button:hover,
.link-button:focus-visible { color: var(--text); }

.client-title {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

/* --- Bookings ------------------------------------------------------------------ */

input[type='date'],
input[type='time'] {
  color-scheme: dark;
}

.booking-intro { margin: 0 0 var(--space-5); }

.booking-list,
.booking-mini {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.booking-list__item {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

.booking-list__main { display: grid; gap: 0.2rem; min-width: 0; }
.booking-list__main .tiny { color: var(--text-3); }
.booking-list__main .booking-list__agreed { color: var(--ok); }
.booking-list__side { display: grid; justify-items: end; gap: 0.5rem; }

@media (max-width: 700px) {
  /* The status gets a line of its own under the details, on every card alike.
     Left to wrap, it sat beside the title on a short card and under the text
     on a long one, and the cancel link, pushed to the end of a column only as
     wide as the badge, hung in the middle of the card. */
  .booking-list__side {
    flex: 1 1 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-4);
  }

  .booking-list__side .link-button { min-height: 44px; }
}

.booking__reply {
  margin: 0.5rem 0 0;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  background: var(--ink-700);
  color: var(--text-2);
  font-size: var(--step--1);
}

.booking__answer {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

.booking__answer .field { margin-bottom: 0; }

/* A short box for the message: the 160px every other form uses pushed the
   answer buttons below a 900px-tall window. Three lines, and it still
   stretches. */
.booking__answer textarea.field__control { min-height: 6.5rem; }

.booking__when {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-3);
}

.booking__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.booking__answer .booking__actions { margin-top: 0; }

/* On a phone the answer buttons keep a little less side padding: at 360px
   "Confirmar" and "Cancelar encomenda" came 2px short of sharing a row, and
   the second went under the first on its own. */
@media (max-width: 560px) {
  .booking__actions .btn { padding-inline: var(--space-3); }
}

.booking-mini a {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  text-decoration: none;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.booking-mini a:hover { border-color: var(--line-strong); color: var(--text); }
.booking-mini svg { color: var(--red-300); }
.booking-mini strong { color: var(--text); }

/* --- Prices (admin/prices) -------------------------------------------------------
   One part at a time under a row of tabs, each part one form with one save, and
   «Simular um orçamento» under it; from 1440px, beside the shorter parts, in a
   column of its own. Not beside the price list, whose lines need the width. */

/* The tabs: words in a row, the current one on a lighter ground inside a whole
   border, as in Fotografias; no line under one edge. They wrap on a phone
   rather than scroll sideways, so all five stay in sight. */
.price-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin: 0 0 var(--space-5);
}

.price-tabs a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: 0.9375rem;
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease),
    border-color var(--fast) var(--ease);
}

.price-tabs a:hover {
  background: var(--ink-600);
  color: var(--text);
}

.price-tabs a[aria-current='page'] {
  border-color: var(--line-strong);
  background: var(--ink-700);
  color: var(--text);
}

@media (max-width: 700px) {
  .price-tabs { justify-content: center; }
  .price-tabs a { padding: 0 var(--space-2); }
}

.prices-layout {
  display: grid;
  align-items: start;
  gap: 0 var(--space-5);
}

.prices-layout__main { min-width: 0; }

@media (min-width: 1440px) {
  .prices-layout--side { grid-template-columns: minmax(0, 1fr) 20rem; }
  .prices-layout--side .sim { position: sticky; top: var(--space-5); }
}

/* The button Enter presses in a form whose first buttons move and delete
   lines: there, but neither seen nor reached with Tab. */
.price-form__default {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.price-form > .save-bar { margin-bottom: var(--space-5); }

.price-rows__empty {
  margin: 0 0 var(--space-3);
  color: var(--text-2);
  font-size: var(--step--1);
}

.price-rows__add { margin-top: var(--space-2); }

/* A line of the price list: a row of fields under column names while there
   is room, a small card with each field named once there is not. Measured on
   the list's own box, which the side bar and the simulator column share the
   window with. */
.price-rows { container: price-rows / inline-size; }

.price-rows__head,
.price-row {
  display: grid;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.price-rows--session .price-rows__head,
.price-rows--session .price-row {
  grid-template-columns: minmax(8.5rem, 1fr) 6.5rem minmax(0, 1.4fr) minmax(0, 1.1fr) 5.5rem 7rem;
}

.price-rows--print .price-rows__head,
.price-rows--print .price-row {
  grid-template-columns: minmax(0, 1.3fr) 8.5rem minmax(0, 1.6fr) 5.5rem 7rem;
}

.price-rows__head {
  padding-bottom: var(--space-2);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 500;
  white-space: nowrap;
}

.price-rows__head .is-num { text-align: right; }

/* From the top: a line that says what is wrong under one field must not
   push the fields beside it off the line. */
.price-row {
  align-items: start;
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
}

/* The line to type a new one in. */
.price-row--new { border-top-style: dashed; }

.price-row__cell { min-width: 0; }

.price-row__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.price-row .control { width: 100%; }

.control--money {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* A line switched off keeps its fields, a shade quieter. */
.price-row.is-off .control { color: var(--text-3); }

.price-row__cell.is-invalid .control,
.control.is-invalid { border-color: var(--red-500); }

.price-row__cell .field__error { margin-top: 0.3rem; }

.price-row__cell--on .choice {
  min-height: 40px;
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
}

.price-row__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 2px;
  min-height: 40px;
}

.price-row__icon {
  width: 36px;
  min-height: 36px;
  padding: 0;
}

.price-row__icon--up svg { transform: rotate(180deg); }

.price-row__icon:disabled { opacity: 0.25; }

.price-row__icon--remove:hover:not(:disabled) {
  --btn-fg: var(--red-300);
  --btn-bg: var(--red-tint);
}

.price-row__warn {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--warn);
  font-size: var(--step--1);
}

@container price-rows (max-width: 46rem) {
  .price-rows__head { display: none; }

  .price-rows--session .price-row,
  .price-rows--print .price-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    padding: var(--space-4) 0;
  }

  .price-row__label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip: auto;
    display: block;
    margin-bottom: 0.35rem;
    color: var(--text-2);
    font-size: var(--step--1);
    font-weight: 500;
  }

  .price-rows--print .price-row__cell--text { grid-column: 1 / -1; }
}

@container price-rows (max-width: 30rem) {
  .price-rows--session .price-row,
  .price-rows--print .price-row { grid-template-columns: minmax(0, 1fr) 7rem; }

  .price-row__cell--text { grid-column: 1 / -1; }
}

/* A discount for quantity reads as the sentence it is. */
.tier-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
}

.tier-row.price-row--new { border-top-style: dashed; }

/* .control, later in the file, would stretch it across the row. */
.tier-row .tier-row__number {
  flex: 0 0 5rem;
  width: 5rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.tier-row__word { color: var(--text-2); }

.tier-row__arrow {
  display: inline-flex;
  color: var(--text-3);
}

.tier-row .price-row__icon { margin-left: auto; }

.tier-row__error {
  flex-basis: 100%;
  margin: 0;
}

/* The loyalty card: what it does in one line, the switch, and beside them
   the card as the client area draws it. */
.loyalty-form__state {
  margin: 0 0 var(--space-4);
  color: var(--text);
  font-size: 0.9375rem;
}

.loyalty-form__switch {
  min-height: 44px;
  margin-bottom: var(--space-4);
  color: var(--text);
  font-size: 0.9375rem;
}

.loyalty-form:has([name='loyalty_on']:not(:checked)) .loyalty-form__fields { opacity: 0.5; }

.loyalty-preview__card {
  padding: var(--space-4);
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

/* Campaigns: one line each, with its form behind «Editar». */
.campaign-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.campaign { padding-top: var(--space-4); }

.campaign + .campaign {
  margin-top: var(--space-2);
  border-top: 1px solid var(--line);
}

.campaign__line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.campaign__name { font-size: 1rem; }

.campaign.is-quiet .campaign__name { color: var(--text-2); }

.campaign__facts {
  margin: 0.35rem 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* Qualified: .more, later in the file, draws a hairline above itself. */
.campaign .campaign__edit {
  margin-top: var(--space-1);
  border-top: 0;
}

.campaign-form > .field__error { margin-top: var(--space-3); }

/* The rule: two choices, each with its worked example. */
.rule-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  border: 0;
}

.rule-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.rule-choice:hover { border-color: var(--text-3); }

.rule-choice:has(input:checked) {
  background: var(--ink-600);
  border-color: var(--red-500);
}

.rule-choice input {
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0.15rem 0 0;
  accent-color: var(--red-500);
}

.rule-choice__text {
  display: grid;
  gap: 0.25rem;
}

.rule-choice__text span {
  color: var(--text-2);
  font-size: var(--step--1);
}

.discount-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.discount-list li + li { border-top: 1px solid var(--line); }

.discount-list a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 48px;
  color: var(--text);
}

.discount-list__name {
  flex: 1 1 auto;
  min-width: 0;
}

.discount-list__value {
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

.discount-list svg {
  flex-shrink: 0;
  color: var(--text-3);
}

.discount-list a:hover .discount-list__name {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* «Simular um orçamento»: the questions, and the answer as a small receipt
   beside them when the box is wide enough. */
.sim { container: sim / inline-size; }

.sim__form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--space-4);
  align-items: end;
}

.sim__form .field { margin: 0; }

.sim .field__control {
  min-height: 44px;
  padding-block: 0.55rem;
  font-size: 0.9375rem;
}

.sim__field--wide { grid-column: 1 / -1; }

.sim__result { margin-top: var(--space-5); }

@container sim (min-width: 44rem) {
  .sim__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    gap: var(--space-5);
    align-items: start;
  }

  .sim__result { margin-top: 0; }
}

.receipt {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.receipt__line,
.receipt__total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  padding: 0.35rem 0;
}

.receipt dt {
  min-width: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.receipt dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.receipt__total {
  margin-top: 0.35rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--line-strong);
}

.receipt__total dt {
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
}

.receipt__total dd {
  font-size: 1.25rem;
  font-weight: 600;
}

.sim__start,
.sim__note,
.sim__rule {
  margin: var(--space-3) 0 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.sim__start {
  margin: 0;
  padding: var(--space-4);
  color: var(--text-2);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-2);
}

.sim__note { color: var(--warn); }

.price-note {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 var(--space-5);
  padding: 0.8rem 1rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.price-note svg { flex-shrink: 0; color: var(--ok); }

/* The loyalty card: one stamp per session, the last place the reward. */
.loyalty__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

.loyalty__title { margin: 0; font-size: var(--step-1); }

.loyalty__stamps {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: var(--space-4) 0;
  padding: 0;
  list-style: none;
}

.loyalty__stamp {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px dashed var(--line-strong);
  border-radius: 50%;
  color: var(--text-3);
}

.loyalty__stamp.is-reward { border-color: var(--red-400); color: var(--red-300); }

.loyalty__stamp.is-stamped {
  border-style: solid;
  border-color: var(--red-400);
  background: var(--red-tint);
  color: var(--red-300);
}

.loyalty__ready {
  margin: var(--space-3) 0 0;
  padding: 0.6rem 0.9rem;
  border-radius: var(--r-2);
  background: var(--ok-tint);
  color: #8FD3B4;
}

/* --- Films in an album (admin) -------------------------------------------------- */

.film-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.film-card {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

.film-card--archived { opacity: 0.72; }

.film-card__poster {
  position: relative;
  display: grid;
  place-items: center;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  border-radius: var(--r-1);
  background: var(--ink-900);
  color: var(--text-3);
}

.film-card__poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.film-card__duration {
  position: absolute;
  right: 6px;
  bottom: 6px;
  padding: 0.1rem 0.35rem;
  border-radius: var(--r-1);
  background: rgba(20, 21, 31, 0.8);
  color: rgba(237, 242, 244, 0.92);
  font-family: var(--font-display);
  font-size: 0.625rem;
  font-variant-numeric: tabular-nums;
}

.film-card__body {
  display: grid;
  align-content: start;
  gap: 0.35rem;
  min-width: 0;
}

.film-card__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.film-card__note { color: var(--text-3); }
.film-card.is-poster-failed .film-card__note { color: var(--red-300); }

.film-card__caption {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.film-card__caption .control { flex: 1 1 14rem; }

.film-card__restore {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.film-card__restore .control { flex: 1 1 12rem; }

.film-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.film-card__pick { cursor: pointer; }
.film-card__pick.is-busy { opacity: 0.6; }

.film-upload,
.film-incoming {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.film-upload .field__label,
.film-upload .tiny,
.film-progress { flex: 1 1 100%; }

.film-upload .control { flex: 1 1 18rem; }

.film-progress {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.film-progress__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(6rem, 12rem) auto auto;
  align-items: center;
  gap: var(--space-3);
}

.film-progress__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--step--1);
}

.film-progress__row progress {
  width: 100%;
  height: 6px;
  accent-color: var(--red-500);
}

.film-progress__note {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.film-progress__row.is-failed .film-progress__note { color: var(--red-300); }

/* Waiting for the site to come back (app.js, films): said in the colour of a
   warning, not of a failure — nothing is lost — with «Retomar» at the end of
   the row to ask again at once. The line under a batch that did not all
   arrive is a sentence and its button, not a row of the grid. Why a film
   stopped is a sentence too, and takes a line of its own under the name and
   the bar, rather than squeezing the name to a letter. */
.film-progress__row.is-waiting .film-progress__note { color: var(--warn); }
.film-progress__row.is-failed .film-progress__note { grid-column: 1 / -1; }

.film-progress__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

@media (max-width: 640px) {
  .film-card {
    grid-template-columns: 96px minmax(0, 1fr);
    gap: var(--space-3);
  }

  .film-progress__row { grid-template-columns: minmax(0, 1fr) auto; }
  .film-progress__row progress { grid-column: 1 / -1; }
  .film-progress__resume { grid-column: 1 / -1; justify-self: start; }
}

/* --- Print orders ------------------------------------------------------------- */

.order-all {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-4);
  padding: 0.75rem 0.9rem;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.order-all .control { width: auto; }

.order-lines {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.order-line {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto 5rem;
  align-items: center;
  gap: var(--space-3);
  padding: 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

.order-line img {
  width: 64px;
  height: 64px;
  border-radius: 6px;
  object-fit: cover;
}

.order-line__name {
  overflow: hidden;
  color: var(--text-2);
  font-size: var(--step--1);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.order-line .control { width: 100%; }

@media (max-width: 560px) {
  /* The size gets the whole width under the photograph. Squeezed between the
     thumbnail and the copies it had 146px at 390, and "15 × 20 cm — 4,50 €"
     read "— 4,5", at 360 "— 4": a price that is not the price. These are the
     controls the page is for, so they are thumb-sized too. */
  .order-line {
    grid-template-columns: 56px minmax(0, 1fr) 4.5rem;
    row-gap: var(--space-2);
  }

  .order-line img { width: 56px; height: 56px; }
  .order-line__name { grid-column: 2 / -1; }
  .order-line select.control { grid-column: 1 / 3; }

  .order-line .control,
  .order-all .control,
  .order-all .btn { min-height: 44px; }
}

.order-delivery {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: 0 0 var(--space-4);
  padding: 0;
  border: 0;
}

/* Three grids in a row — the chosen way's fields, then what every order asks —
   with nothing between them: the phone's label sat right under the time field
   above it, where every other field is a full gap away. Above the first grid
   the margin folds into the one under the choice. */
.order-delivery ~ .form-grid { margin-top: var(--space-4); }

.choice {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  cursor: pointer;
}

.choice input { accent-color: var(--red-500); }

/* «Guardar também no meu perfil», under the number it would keep. */
.phone-keep {
  display: flex;
  margin-top: 0.25rem;
  font-size: var(--step--1);
  color: var(--text-2);
}

.order-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

.order-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.4rem;
}

.order-thumbs img {
  width: 44px;
  height: 44px;
  border-radius: 4px;
  object-fit: cover;
}

.order-table { margin: var(--space-4) 0 0; }
.order-table td { vertical-align: middle; }
.order-table__thumb { width: 52px; }

/* Whole at every width: the reset lets an image shrink with its cell, and the
   cell's 52px included its padding, which left a 28px sliver of the print. */
.order-table__thumb img {
  display: block;
  width: 44px;
  max-width: none;
  height: 44px;
  border-radius: 4px;
  object-fit: cover;
}

.detail-list--inline {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-top: 0;
}

@media (max-width: 560px) {
  /* Five columns do not fit a phone: the size broke onto four lines and the
     file names mid-word. Each line becomes two rows beside its thumbnail,
     the name across the top and the size, copies and price under it. */
  .order-table,
  .order-table tbody { display: block; }

  .order-table tr {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) auto minmax(4.5rem, auto);
    align-items: center;
    gap: var(--space-1) var(--space-3);
    padding-block: var(--space-3);
    border-bottom: 1px solid var(--line);
  }

  .table.order-table td { padding: 0; border: 0; }
  .order-table .order-table__thumb { grid-row: span 2; width: auto; }
  .order-table td:nth-child(2) { grid-column: 2 / -1; overflow-wrap: anywhere; }

  /* Two answers to a row, not one: a day or a head count sat alone on a line
     each. The space under the last row is taken back, so the list ends where
     it always did. */
  .booking .detail-list--inline {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 var(--space-4);
    margin-bottom: calc(var(--space-3) * -1);
  }

  /* Label and value each on a row the pair shares, so a label that wraps
     onto two lines does not push its value below the one beside it. */
  .booking .detail-list--inline > div {
    display: grid;
    grid-row: span 2;
    grid-template-rows: subgrid;
    margin-bottom: var(--space-3);
  }

  /* The first is the long one and keeps the whole width; so does a last one
     left without a partner, rather than wrapping in half a row. */
  .booking .detail-list--inline > div:first-child,
  .booking .detail-list--inline > div:nth-child(even):last-child { grid-column: 1 / -1; }
}

.stat--accent { border-color: var(--red-tint-2); }
.stat--accent .stat__value { color: var(--red-300); }

.dropzone {
  display: grid;
  place-items: center;
  gap: var(--space-3);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-3);
  text-align: center;
  color: var(--text-2);
  cursor: pointer;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.dropzone:hover,
.dropzone.is-dragging {
  border-color: var(--red-500);
  background: var(--red-tint);
}

.dropzone input { display: none; }

.dropzone__files {
  font-size: var(--step--1);
  color: var(--text-3);
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.toolbar__search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0 0.85rem;
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
}

.toolbar__search input {
  width: 12rem;
  max-width: 40vw;
  background: none;
  border: 0;
  outline: none;
  font-size: var(--step--1);
}

/* The tabs over a list, on a phone. The photograph tabs wrapped onto four or
   five centred rows, a third of the screen before the first photograph, and
   the three states of a request onto two. One row instead, scrolling sideways
   inside itself (the page does not) and running out to the edges of the
   screen, so the pill cut off at the edge says there are more. The side
   margin is the main's own padding. At 44px they are easier to hit than they
   were. app.js brings the current tab into view when it is further along. */
@media (max-width: 700px) {
  .toolbar .filters {
    flex: 1 1 100%;
    flex-wrap: nowrap;
    justify-content: flex-start;
    min-width: 0;
    margin-inline: calc(clamp(1rem, 3vw, 2.5rem) * -1);
    padding-inline: clamp(1rem, 3vw, 2.5rem);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }

  .toolbar .filters::-webkit-scrollbar { display: none; }

  .toolbar .filter {
    flex: none;
    min-height: 44px;
    white-space: nowrap;
  }
}

/* The tabs fade into the edge of the screen on the side where the row goes
   on, and only there: at 360px the cut fell in the gap after "Confirmadas",
   so "Todas" was out of sight and nothing looked cut off. At either end of
   the row nothing is dimmed, so a lit tab at the end keeps its colour. Where
   the fade cannot follow the scroll, the row stays as it was. */
@property --fade-before { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-after { syntax: '<length>'; inherits: false; initial-value: 0px; }

@keyframes filters-edges {
  0% { --fade-before: 0px; --fade-after: 3rem; }
  10%, 90% { --fade-before: 3rem; --fade-after: 3rem; }
  100% { --fade-before: 3rem; --fade-after: 0px; }
}

@media (max-width: 700px) {
  @supports (animation-timeline: scroll()) {
    .toolbar .filters {
      -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--fade-before), #000 calc(100% - var(--fade-after)), transparent);
      mask-image: linear-gradient(to right, transparent, #000 var(--fade-before), #000 calc(100% - var(--fade-after)), transparent);
      animation: filters-edges linear both;
      animation-timeline: scroll(self inline);
    }
  }
}

/* Shift + click selects a range; without this it also selects the text of
   everything in between. */
.select-toggle {
  user-select: none;
}

/* --- The photograph sheet ---------------------------------------------------
   A <dialog>. The browser gives the backdrop, the escape key, the focus trap
   and the inertness of the page behind for nothing, which in a project with no
   framework is most of the work. With JavaScript off the server renders it
   open, and the rule below drops it back into the normal flow of the page. */

.sheet {
  width: min(34rem, calc(100vw - 2rem));
  max-height: min(44rem, 90svh);
  padding: 0;
  background: var(--ink-700);
  color: var(--text);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-4);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}

.sheet::backdrop { background: rgba(10, 11, 16, 0.72); }

dialog[open]:not(:modal) {
  position: static;
  margin: 0 0 var(--space-5);
}

.sheet__form {
  display: flex;
  flex-direction: column;
  max-height: inherit;
}

.sheet__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-bottom: 1px solid var(--line);
}

.sheet__name {
  flex: 1;
  min-width: 0;
  font-size: var(--step--1);
  color: var(--text-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet__body {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-4);
  overflow-y: auto;
}

.sheet__group {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  border: 0;
}

.sheet__group legend {
  padding: 0;
  margin-bottom: var(--space-2);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.sheet__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  border-top: 1px solid var(--line);
  background: var(--ink-800);
}

.sheet__foot .btn--primary { margin-inline-start: auto; }

@media (max-width: 560px) {
  /* Full width at the bottom of the screen, where a thumb reaches. */
  .sheet {
    width: 100vw;
    max-width: 100vw;
    max-height: 88svh;
    margin: auto auto 0;
    border-radius: var(--r-4) var(--r-4) 0 0;
    border-bottom: 0;
  }
}

/* The small number box that sets a film's place on the homepage. */
.control--order { width: 4.5rem; }

.control {
  width: 100%;
  min-height: 40px;
  padding: 0.5rem 0.7rem;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text);
  font-size: var(--step--1);
}

.control:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

select.control {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23A6B0C3' stroke-width='2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  padding-right: 2rem;
}

/* Switch */

.switch {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--step--1);
  color: var(--text-2);
  cursor: pointer;
  user-select: none;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.switch__track {
  position: relative;
  width: 38px;
  height: 22px;
  flex-shrink: 0;
  background: var(--ink-400);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.switch__track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: var(--text-2);
  border-radius: 50%;
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}

.switch input:checked + .switch__track {
  background: var(--red-500);
  border-color: var(--red-500);
}

.switch input:checked + .switch__track::after {
  background: #fff;
  transform: translateX(16px);
}

.switch input:focus-visible + .switch__track {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  border-radius: var(--r-full);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.badge--ok { background: var(--ok-tint); color: var(--ok); }
.badge--warn { background: var(--warn-tint); color: var(--warn); }
.badge--muted { background: var(--ink-500); color: var(--text-3); }
.badge--solid { background: rgba(20, 21, 31, 0.75); color: #fff; backdrop-filter: blur(6px); }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.table th,
.table td {
  padding: 0.9rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.table th {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}

.table tbody tr:hover { background: var(--ink-600); }

.table td:last-child { text-align: right; }

.form-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  /* Aligned from the top, not the bottom. Fields that carry a line of help
     underneath are taller, and bottom alignment pushed their labels and inputs
     out of line with the fields beside them. */
  align-items: start;
}

.form-grid .field { margin-bottom: 0; }

/* A field that needs the whole row: a summary, or a switch with an explanation. */
.form-grid .field--wide,
.form-grid__actions { grid-column: 1 / -1; }

/* A button sitting directly in the grid still lines up with the inputs beside
   it, rather than floating to the top now that the fields align from there. */
.form-grid > .btn { align-self: end; }

.form-grid .field--wide .switch { align-items: flex-start; }

.form-grid .field--wide .switch .field__hint { display: block; margin-top: 2px; }

/* .table th sets its own alignment and outranks a single class: the heading
   over the buttons stood at the left of its column while they stood at the
   right. */
.table .table__right { text-align: right; }

/* A list table on a phone. Up to 700px a list of clients, albums or messages
   kept its columns, so a name broke over three lines and the button that
   opens the row — the reason for the list — was off the right edge. Stacked,
   each row reads as its name with that button beside it, then whatever needs
   a line of its own, then the figures with their column's name in front of
   them. */
@media (max-width: 700px) {
  .table--stack thead { display: none; }

  .table--stack,
  .table--stack tbody { display: block; }

  .table--stack tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-4) 0;
    border-bottom: 1px solid var(--line);
  }

  /* The name and its button are the first line whatever follows them; without
     this the figures of a short row climbed up beside the name and squeezed it
     to a word a line. */
  .table--stack tr::after {
    content: "";
    order: -1;
    flex-basis: 100%;
  }

  .table--stack tbody tr:hover { background: none; }

  .table--stack td {
    padding: 0;
    border: 0;
    text-align: left;
  }

  .table--stack td:first-child {
    order: -2;
    flex: 1 1 0;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .table--stack td:last-child { margin-left: auto; }
  .table--stack td:last-child:has(.btn) { order: -1; }
  /* An address or a link has no space to break at, and a long one ran past
     the card and set the whole list scrolling sideways. On its own line it
     breaks where it must. */
  .table--stack .table__line {
    flex: 1 0 100%;
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .table--stack td[data-label]::before {
    content: attr(data-label);
    margin-right: 0.4em;
    font-family: var(--font-display);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-3);
  }

  .table--stack td:last-child .btn { min-height: 44px; }
}

/* The album list. A date is one word: broken at its hyphens it read as two.
   Nor does a state break inside its pill. */
.table--albums td:nth-child(2),
.table--albums .badge { white-space: nowrap; }

/* Between a phone and a wide screen the columns come close to the width of
   the panel, and whole dates and states made them wider still: at 768px the
   buttons went under the edge. A little less padding keeps them inside. */
@media (min-width: 701px) and (max-width: 999px) {
  .table--albums th,
  .table--albums td { padding-inline: 0.5rem; }
}

/* Drag & drop ordering */

.order-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-3);
}

/* On a client's page the photographs are only a reminder of what they can see,
   not something to reorder, so on a phone three to a row is plenty — one to a
   row pushed the discount and the password a screen further down for every
   photograph. */
@media (max-width: 560px) {
  .order-list--thumbs {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-2);
  }
}

.order-item {
  position: relative;
  aspect-ratio: 3 / 2;
  border-radius: var(--r-2);
  overflow: hidden;
  background: var(--ink-600);
  cursor: grab;
}

.order-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.order-item.is-dragging { opacity: 0.4; }

.order-item.is-over { outline: 2px dashed var(--red-500); outline-offset: -2px; }

.order-item__index {
  position: absolute;
  top: 8px;
  left: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 26px;
  padding: 0 6px;
  background: rgba(20, 21, 31, 0.75);
  border-radius: var(--r-full);
  font-family: var(--font-display);
  font-size: 0.75rem;
  backdrop-filter: blur(6px);
}

/* Toast */

.toast-stack {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 130;
  display: grid;
  gap: 0.5rem;
  pointer-events: none;
}

.toast {
  padding: 0.75rem 1rem;
  background: var(--ink-500);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  box-shadow: var(--shadow-2);
  font-size: var(--step--1);
  animation: toast-in var(--base) var(--ease);
}

/* Two classes, so it holds against the later .toast block's border. */
.toast.toast--error { border-color: var(--red-400); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* --- Print ----------------------------------------------------------------- */

@media print {
  .site-header,
  .site-footer,
  .cookie,
  .lightbox { display: none !important; }

  body { background: #fff; color: #000; }
}

/* --- Albums ------------------------------------------------------------------ */

.album-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-4);
}

.album-card {
  display: flex;
  flex-direction: column;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
  transition: border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.album-card:hover {
  border-color: var(--red-tint-2);
  transform: translateY(-2px);
}

.album-card__media {
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--ink-700);
}

.album-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cover-x, 50%) var(--cover-y, 50%);
  transform-origin: var(--cover-x, 50%) var(--cover-y, 50%);
  transform: scale(var(--cover-zoom, 1));
}

/* «Enquadrar a capa» on the album's page: the two shapes the cover is shown
   in, the photograph dragged inside the larger one, and the three sliders. */
.cover-frame {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.cover-frame__title {
  margin: 0;
  font-weight: 600;
}

.cover-frame__shapes {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}

.cover-frame__shape {
  display: grid;
  gap: 0.35rem;
  margin: 0;
}

.cover-frame__shape figcaption { color: var(--text-3); }

.cover-frame__box {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--ink-600);
  border-radius: var(--r-1);
}

.cover-frame__box--site {
  width: min(320px, 100%);
  aspect-ratio: 4 / 3;
  cursor: grab;
  touch-action: none;
}

.cover-frame__box--site:active { cursor: grabbing; }

.cover-frame__box--client {
  width: 180px;
  aspect-ratio: 3 / 2;
}

.cover-frame__box img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cover-x, 50%) var(--cover-y, 50%);
  transform-origin: var(--cover-x, 50%) var(--cover-y, 50%);
  transform: scale(var(--cover-zoom, 1));
  user-select: none;
  pointer-events: none;
}

.cover-frame__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2) var(--space-4);
}

.cover-frame__field {
  display: grid;
  gap: 0.25rem;
  min-width: 9rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.cover-frame__field input { accent-color: var(--red-500); }

.album-card__body {
  display: block;
  padding: var(--space-4);
}

.album-card__title {
  display: block;
  font-family: var(--font-display);
  font-size: 0.95rem;
  margin-bottom: 2px;
}

.album-card__state {
  display: block;
  margin-top: var(--space-3);
}

/* Says why something cannot be done yet, without looking like an error. */
.notice {
  margin-bottom: var(--space-6);
  padding: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-600);
}

.notice--warn { border-color: var(--warn-tint); }

.notice h2 {
  margin: 0 0 var(--space-3);
  font-size: 1.0625rem;
}

.notice p {
  margin: 0 0 var(--space-4);
  max-width: 60ch;
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.notice__price {
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--text);
}

.notice__list {
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

.notice__list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--line);
}

.notice__list li:last-child { border-bottom: 0; }

/* Searchable picker: scales to a long client list without endless scrolling. */
.picker__filter { margin-bottom: var(--space-3); }

.picker__list {
  max-height: 280px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.picker__row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

.picker__row:last-child { border-bottom: 0; }
.picker__row:hover { background: var(--ink-600); }
.picker__row input { accent-color: var(--red-500); }
.picker__name { font-size: 0.9rem; }
.picker__meta { margin-left: auto; font-size: var(--step--1); color: var(--text-3); }
.picker__row[hidden] { display: none; }

/* The address never gave way, so on a phone it squeezed the name onto two or
   three lines, and a real address, longer than example.com, ran out of the
   list. The two share a line when they fit; otherwise the address goes under
   the name and breaks where it must. On a phone it always goes under, so the
   names read down one straight edge. */
.picker__who {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--space-3);
  min-width: 0;
}

.picker__who .picker__meta {
  margin-left: 0;
  overflow-wrap: anywhere;
}

@media (max-width: 560px) {
  .picker__who {
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.35;
  }

  /* Every client takes two lines here, and the 280px that had room for six
     of them held four, the fifth cut in half. Tighter rows and a taller list
     make room for six again before it scrolls. */
  .picker__list { max-height: 22rem; }
  .picker__row { padding-block: var(--space-2); }
}

.order-item--pick .order-item__check {
  position: absolute;
  top: 8px;
  right: 8px;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  background: rgba(20, 21, 31, 0.7);
  border: 1px solid rgba(237, 242, 244, 0.4);
  border-radius: 50%;
  color: transparent;
}

.order-item--pick:has(input:checked) { outline: 2px solid var(--red-500); outline-offset: -2px; }
.order-item--pick:has(input:checked) .order-item__check {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

/* --- Gallery filter bar ---------------------------------------------------------
   Sticks under the header so the categories stay reachable while scrolling a long
   archive. */

.filters--sticky {
  position: sticky;
  top: var(--header-h);
  z-index: 30;
  margin-inline: calc(clamp(1rem, 3.5vw, 2.75rem) * -1);
  padding: var(--space-3) clamp(1rem, 3.5vw, 2.75rem);
  background: rgba(27, 29, 43, 0.86);
  backdrop-filter: blur(12px) saturate(140%);
  border-bottom: 1px solid var(--line);
}

@supports not (backdrop-filter: blur(1px)) {
  .filters--sticky { background: var(--ink-800); }
}

/* --- Saving deterrents ----------------------------------------------------------
   Applied to the public pages only: the client area is meant to be downloaded.
   None of this defeats a screenshot, it just stops the casual drag-and-save.
   -------------------------------------------------------------------------------- */

.is-protected img {
  -webkit-user-drag: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* A transparent layer sits over each frame, so "save image as" and long-press
   land on an empty element rather than on the photograph. */
.shield {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: block;
  background: transparent;
}

/* Inside the frame now, so it covers the print and nothing else. */
.shield--stage {
  position: absolute;
  inset: 0;
  z-index: 3;
}

.is-protected .tile__open { cursor: zoom-in; }

/* --- Centring on a phone -----------------------------------------------------
   Deliberately a short list. Centring everything is the failure here: a
   paragraph read down a ragged centre is harder work than one with a straight
   left edge, a centred form label floats away from the control it names, and a
   table column read down a centred edge stops being a column.

   So what is centred is display type, single-line labels, pill rows and the
   small print under a card — things the eye takes in at once. Running text
   (.prose, .lead, .collection__body), every .field, and .table are left as they
   are on purpose. */

@media (max-width: 700px) {
  .admin__head h1,
  .page-head h1,
  .page-head > .eyebrow { flex: 1 0 100%; text-align: center; }

  /* Most heads in the two panels wrap their title in a block with a way back,
     an eyebrow or a line under it, and the rule above never reached through
     it: the block shrank to the title and was centred whole, so the short
     line above hung off the title's left edge. A full row, centred as a
     column: single lines sit over the middle, and a line long enough to wrap
     fills the width and keeps its left edge. */
  .admin__head > div:first-child {
    flex: 1 0 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* The same reach, for the public pages: a page head is an eyebrow, a title
     and a line of small print, and on a phone they are read as three lines
     down the middle — not as a title with the count hung off its side. The
     rule above only ever reached a title that was a direct child, and on these
     pages it is wrapped with its eyebrow, so the pair shrank to their own width
     and the count was left sitting on the title's baseline. Each takes a full
     row instead. Running text inside a stacked head keeps its left edge (see
     .page-head--stacked .lead below). */
  .page-head > div:first-child,
  .page-head > p { flex: 1 0 100%; text-align: center; }

  .page-head { row-gap: var(--space-3); }

  /* A client's picture, name and state, centred together on the title line. */
  .client-title { flex-wrap: wrap; justify-content: center; }

  /* The loyalty card's head is a panel head in all but name. */
  .admin__head,
  .page-head,
  .panel__head,
  .loyalty__head { justify-content: center; }

  .admin__head .page-head__actions { justify-content: center; }

  .hero__inner { justify-content: center; text-align: center; }
  .hero__line { margin-inline: auto; }

  .stream__head,
  .band__inner,
  .cta-band { justify-content: center; text-align: center; }

  .band__title { margin-inline: auto; }

  .filters,
  .loyalty__stamps { justify-content: center; }

  .stat,
  .album-card__body { text-align: center; }

  .site-footer__inner { justify-items: center; text-align: center; }
  .site-footer__links,
  .site-footer__base { justify-content: center; text-align: center; }

  .focus-card__brand { display: flex; justify-content: center; }
  .focus-card > .eyebrow,
  .focus-card > h1,
  .focus-card__foot { text-align: center; }

  .qr { margin-inline: auto; }

  /* About and Contact build their heading by hand instead of using .page-head,
     so they are named directly. Only the two lines of display type: the prose,
     the .lede and the definition list under them keep their left edge, which is
     the whole point of doing this by hand. */
  .about > .reveal > .eyebrow,
  .about > .reveal > h1,
  .contact > .reveal > .eyebrow,
  .contact > .reveal > h1 { text-align: center; }

  /* The one thing that needs putting back: it sits inside a container that is
     now centred, and it is a paragraph. */
  .page-head--stacked .lead { text-align: left; }
}

/* --- Getting in: the password field and the card door ------------------------
   Six families in seven never got into the client area from a letter. What
   they met was a password copied off paper into a box of dots, and nothing
   pointing a family with a card at the right door. Each of these is one of
   those, fixed. The line naming the photographer under every sign-in form went
   again at Hugo's request: it read as something stuck on, not as trust. */

.reveal-field {
  position: relative;
}

.reveal-field .field__control {
  padding-right: 3.25rem;
}

.reveal-field__toggle {
  position: absolute;
  top: 50%;
  right: 0.35rem;
  transform: translateY(-50%);
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}

.reveal-field__toggle:hover,
.reveal-field__toggle:focus-visible { color: var(--text); }

.reveal-field__eye-off,
.reveal-field__toggle[aria-pressed="true"] .reveal-field__eye { display: none; }

.reveal-field__toggle[aria-pressed="true"] .reveal-field__eye-off { display: inline-flex; }

.claim-door {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

.claim-door p {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* On a card's account step, the other way on — «Já tenho conta — entrar», or
   back to «Criar conta» — set apart from the form by space alone. */
.claim-switch {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-7);
}

.claim-switch p {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* A claim code is fourteen characters with its dashes: at the six-digit code's
   spacing it runs off a telephone. */
.field__control--claim {
  font-size: 1.0625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.field__control--claim::placeholder {
  letter-spacing: 0.08em;
}

/* Whose photographs, from which match, how many — said before anything is
   asked for, because it is the reason to bother. */
.claim-facts {
  margin: calc(-1 * var(--space-2)) 0 var(--space-4);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--red-300);
}

/* A card for photographs that are given away says so before the family types
   anything: what arrives is theirs to take, not a set to be waited for. */
.claim-free {
  margin: calc(-1 * var(--space-3)) 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: rgba(217, 4, 41, 0.1);
  border: 1px solid var(--red-tint-2);
  border-radius: var(--r-2);
  color: var(--text);
  font-size: var(--step--1);
}

/* --- A person's envelope on /resgatar/conta (migration 036) ----------------------
   The line that says the next albums come too, under what is waiting now. Room
   of its own below, because .claim-free pulls itself up with a negative top
   margin to sit under the facts line. Place after .claim-free in app.css. */

.claim-future {
  margin: calc(-1 * var(--space-2)) 0 var(--space-5);
  color: var(--text-2);
}

/* The account a card is about to join, named before anything is pressed. */
.claim-who {
  display: grid;
  gap: 0.15rem;
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

.claim-who span { color: var(--text-3); font-size: var(--step--1); }

/* --- People, shares and cards in the panel ---------------------------------- */

.people-progress {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.people-progress p { margin: 0; }

.inline-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.inline-form .field__control {
  width: auto;
  flex: 1 1 14rem;
  min-width: 0;
}

.field__control--sm {
  min-height: 40px;
  padding: 0.45rem 0.7rem;
  font-size: var(--step--1);
}

.inline-form .field__control--sm { flex: 0 1 14rem; }

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

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

.row-more__body {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

.row-more__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}


/* The envelopes page: the button that prints, and beside it the one sentence
   to read before pressing it. */
.envelope-go {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  margin-top: var(--space-5);
}

.envelope-go p {
  flex: 1 1 16rem;
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}


/* «Estes envelopes libertam as fotografias», under the fields it belongs to. */
.envelope-free { margin-top: var(--space-4); }


/* On the family's own album: whose photographs these are. */
.narrowed-note {
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
  color: var(--text-2);
}

.redeem-panel { margin-top: var(--space-7); }

/* --- The sheet of envelopes ----------------------------------------------------
   Meant for paper: white ground, black type, dashed lines to cut along. Eight
   to an A4 page — two across, four down, 95 × 68 mm each inside the 10 mm
   margin — and every eight a .cards-sheet of its own that ends the page, so
   the cut lines fall in the same place on every sheet whatever a card holds.
   The card's height is fixed for that reason, and what is on it is sized to
   fit with room to spare. On screen it looks like the sheets that will come
   out of the printer. */

.print-body {
  background: #f4f4f1;
  color: #14151f;
}

.sheet-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  max-width: 190mm;
  margin: var(--space-5) auto;
  padding: 0 var(--space-4);
}

.sheet-bar a { color: #14151f; }
.sheet-bar p { flex-basis: 100%; margin: 0; color: #4a4d63; }
.sheet-bar strong { color: #14151f; }

.cards-sheet {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 68mm;
  width: 190mm;
  margin: 0 auto var(--space-6);
  background: #fff;
  border-top: 1px dashed #9a9cab;
  border-left: 1px dashed #9a9cab;
  box-shadow: 0 1px 4px rgba(20, 21, 31, 0.12);
}

/* One envelope: a head (who took it, which album), the QR beside whose
   photographs and the two things to type, and a foot across the whole width
   with how to use it. The foot used to sit in the narrow column beside the
   QR, where its last line was cut off by the fixed height. */
.claim-card {
  display: grid;
  /* minmax(0, …): without it the one-line album title widens the column to
     its full length and everything else runs off the envelope's right edge. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: 2.4mm;
  height: 68mm;
  padding: 4.5mm 5mm;
  overflow: hidden;
  border-right: 1px dashed #9a9cab;
  border-bottom: 1px dashed #9a9cab;
  break-inside: avoid;
  page-break-inside: avoid;
  color: #14151f;
}

.claim-card p { margin: 0; }

.claim-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 3mm;
  padding-bottom: 1.8mm;
  border-bottom: 0.25mm solid #d6d7de;
}

.claim-card__site {
  flex: none;
  font-family: var(--font-display);
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #D90429;
}

/* The album by name and date. One line: a long title is cut with an ellipsis
   rather than pushing the code down. */
.claim-card__album {
  min-width: 0;
  overflow: hidden;
  font-size: 7pt;
  color: #4a4d63;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.claim-card__body {
  display: grid;
  grid-template-columns: 24mm minmax(0, 1fr);
  gap: 4mm;
  align-items: center;
  min-height: 0;
}

/* The QR code, and under it a whole-album envelope's label and number. */
.claim-card__side {
  display: grid;
  gap: 1.5mm;
  justify-items: center;
}

.claim-card__qr svg {
  display: block;
  width: 24mm;
  height: 24mm;
}

.claim-card__side .claim-card__number {
  font-size: 7pt;
  font-weight: 700;
  line-height: 1.25;
  text-align: center;
  overflow-wrap: anywhere;
}

.claim-card__main {
  display: grid;
  gap: 2.4mm;
  min-width: 0;
}

.claim-card__who {
  display: grid;
  gap: 0.4mm;
  line-height: 1.2;
}

.claim-card__who span {
  font-size: 7pt;
  color: #4a4d63;
}

/* Two lines at most: a long name must not push the code off the card. */
.claim-card__who strong {
  display: -webkit-box;
  overflow: hidden;
  font-size: 12pt;
  font-weight: 700;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* The two things /resgatar asks for, framed together as the one thing on the
   envelope to copy (migration 028). A whole frame, not a rule down one side. */
.claim-card__keys {
  display: grid;
  gap: 1mm;
  margin: 0;
  padding: 2mm 2.6mm;
  border: 0.3mm solid #14151f;
  border-radius: 1.5mm;
}

.claim-card__keys > div {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 2mm;
}

.claim-card__keys dt {
  font-size: 6.5pt;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #4a4d63;
}

.claim-card__keys dd {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.claim-card__keys .claim-card__ref { font-size: 10.5pt; }

.claim-card__keys .claim-card__code { font-size: 11.5pt; }

.claim-card__foot {
  display: grid;
  gap: 0.8mm;
  font-size: 6.8pt;
  line-height: 1.35;
  color: #4a4d63;
}

/* What the code is for beyond today: this album and every next one. */
.claim-card__foot .claim-card__future {
  font-weight: 600;
  color: #14151f;
}

/* Said on the envelope, because it changes what the family gets. */
.claim-card__foot .claim-card__free {
  font-weight: 600;
  color: #a1041f;
}

@page {
  size: A4;
  margin: 10mm;
}

@media print {
  .print-body { background: #fff; }
  .sheet-bar { display: none; }

  .cards-sheet {
    margin: 0;
    box-shadow: none;
    break-after: page;
  }

  .cards-sheet:last-of-type { break-after: auto; }
}

/* A phone shows the envelopes one under the other, to be read; printed, they
   are laid out as above, because the page is then A4 and not the phone. */
@media screen and (max-width: 760px) {
  .cards-sheet {
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: auto;
    width: auto;
    margin-inline: var(--space-4);
  }

  .claim-card {
    height: auto;
    min-height: 68mm;
  }
}

/* --- Accounts that recover themselves -----------------------------------------
   The address, the second step, and the line that asks for them. All of it is
   made of what the panel already has — panels, form grids, badges, the
   authenticator page's key and QR — so it reads as the same site. The one new
   shape is the list of recovery codes, which has to be copied off a screen. */

/* Under the password field on the sign-in form: the way back, not a feature. */
.login-forgot {
  display: inline-block;
  margin-top: 0.5rem;
  color: var(--text-3);
}

.login-forgot:hover { color: var(--text-2); }

/* One line above the page while the address is unconfirmed. The same thin rule
   as .claim-free, in grey rather than red: it can wait. */
.account-line {
  margin: 0 0 var(--space-4);
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.55;
}

.account-block { margin-bottom: var(--space-5); }

/* «Enviar outro» is for when the mail did not come: said small, under the field. */
.account-block .link-button,
.account-after .link-button { font-size: var(--step--1); }

.account-subhead {
  margin: var(--space-2) 0 var(--space-2);
  font-size: var(--step-0);
}

.account-after { margin-top: var(--space-3); }

/* Six digits, spaced so a slip is visible, in a box no wider than they are. */
.account-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.3em;
}

/* Every form on the account page, and the code on the second step's page.
   One row that wraps: labels above their boxes, and the boxes and the button
   that sends them one height, lined up along the bottom, so a label that runs
   to two lines never pushes its box out of line with the button. Hugo saw the
   old mix (52px boxes, 38px and 48px buttons, some at the top of their cell)
   as buttons not aligned with their boxes. */
.account-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-4);
}

.account-form .field {
  flex: 1 1 13rem;
  min-width: 0;
  margin: 0;
}

/* Six digits: a box no wider than they are. */
.account-form .field--code { flex: 0 1 11rem; }

.account-form .field__control,
.account-form .btn,
.account-done { min-height: 48px; }

.account-form .field__control { padding-block: 0.65rem; }

.account-form > .btn { flex: 0 0 auto; }

/* A code already accepted: the word where its box was, at the box's height. */
.account-done { display: flex; align-items: center; }

.account-form__actions {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

/* «Desligar» sits at the far end, away from the button that is pressed more. */
.account-form__actions .btn--danger { margin-left: auto; }

/* The second step's page: its long label on a line of its own, close above. */
.account-enrol { row-gap: var(--space-2); }
.account-enrol .field__label { flex-basis: 100%; margin: 0; }
.account-enrol .field__control { width: auto; flex: 0 1 11rem; min-width: 0; }

/* A phone: each field takes the row and its button the next, full width; a
   code keeps its button beside it, sharing the row. */
@media (max-width: 560px) {
  .account-form .field:not(.field--code) { flex-basis: 100%; }
  .account-form .field--code { flex: 1 1 8rem; }
  .account-form > .btn { flex: 1 1 auto; }
  .account-form__actions .btn { flex: 1 1 100%; }
  .account-form__actions .btn--danger { margin-left: 0; }
}

.account-switch { flex-basis: 100%; margin-top: var(--space-2); }

/* Ten codes of nine characters, in two columns: short enough to copy by hand,
   in a face where 0 and O cannot be mistaken — though the alphabet has no O. */
.recovery-codes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, max-content));
  gap: var(--space-2) var(--space-6);
  margin: 0 0 var(--space-5);
  padding: var(--space-4) var(--space-5);
  list-style: none;
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-1);
}

.recovery-codes code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.05rem;
  letter-spacing: 0.08em;
  color: var(--text);
  user-select: all;
}

@media (max-width: 480px) {
  .recovery-codes { grid-template-columns: 1fr; }
}

/* --- Clubs --------------------------------------------------------------------
   «Clubes neste álbum» is a panel that folds: closed, on an album with no club,
   it is its heading and one quiet line. The heading is the whole handle. */
.club-panel > summary {
  list-style: none;
  cursor: pointer;
}

.club-panel > summary::-webkit-details-marker { display: none; }

.club-panel > summary h2::after {
  content: "\25B8";
  display: inline-block;
  margin-left: var(--space-2);
  font-size: 0.8em;
  color: var(--text-3);
  transition: transform 0.15s ease;
}

.club-panel[open] > summary h2::after { transform: rotate(90deg); }

.club-panel:not([open]) > summary { margin-bottom: 0; }

.club-panel .alert { margin: 0 0 var(--space-4); }

/* Release and «Tirar do álbum» side by side, wrapping under each other on a
   narrow screen rather than pushing the row wider than the card. */
.club-panel__actions {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
}

.club-panel__title {
  margin: var(--space-5) 0 var(--space-1);
  font-size: var(--step-0);
}

/* One small form per club or account: its name, then its one button. */
.club-panel__choices {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

.club-panel__choices .inline-form { justify-content: space-between; }

.club-panel__choices .inline-form > span { min-width: 0; overflow-wrap: anywhere; }

.club-panel__foot { margin: var(--space-4) 0 0; }

.club-add { margin-bottom: var(--space-4); }

.club-add .field__control { max-width: 32rem; }

/* Stacked on a phone, a linked club's two buttons take a line of their own
   under its name, rather than squeezing «Benfica Sub-10» to a word a line
   beside them. */
@media (max-width: 700px) {
  .club-panel .table--stack td:last-child {
    order: 0;
    flex: 1 0 100%;
    margin-left: 0;
  }

  .club-panel__actions { justify-content: flex-start; }
}

/* «Clube: X» on a family's album card, on a line of its own under the title. */
.album-card__club {
  display: block;
  margin: 2px 0 var(--space-1);
}

/* The storage check on the storage page: one line per finding, in the same
   voice as «Avisos» (a coloured edge says how much it matters), and the
   button that acts on a line at the end of it, wrapping under it on a phone. */
.repair__run { margin: var(--space-3) 0; }

.repair__list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.repair__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.repair__item--warn {
  border-color: rgba(224, 177, 94, 0.45);
  background: var(--warn-tint);
}

.repair__item--error {
  border-color: var(--red-tint-2);
  background: var(--red-tint);
  color: var(--text);
}

.repair__inline { margin: 0; }

/* Long work a request at a time (admin/continue.php): how much is left, and
   the button that carries it on, pressed by the page itself with script. */
.continue p { margin: 0 0 var(--space-3); }

.continue__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* =========================================================================
   The photographer's panel (layouts/admin.php): the shell and the pieces
   every page of it is built from. Each rule that touches a class the
   families' panel also uses (.panel, .admin__head, .empty-state, .attention…)
   is written under .admin--studio, so their area looks exactly as it did.
   ========================================================================= */

/* --- The navigation, grouped ------------------------------------------------
   Four groups by what Hugo is doing. Words, not a row of glyphs: the same list
   is the side bar from 1000px and the sheet «Menu» opens below that. */

.studio-nav__heading {
  margin: 0 0 var(--space-2);
  padding-inline: var(--space-3);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
}

.studio-nav__list {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.studio-nav__link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 38px;
  padding: 0.35rem var(--space-3);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.3;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.studio-nav__link:hover {
  background: var(--ink-600);
  color: var(--text);
}

/* Where you are: the row lit inside a whole border, no rule down one edge.
   (No view uses .studio-nav since the old side bar came back.) */
.studio-nav__link[aria-current='page'] {
  border: 1px solid var(--line-strong);
  background: var(--ink-700);
  color: var(--text);
  font-weight: 600;
}

.studio-nav__label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.studio-nav__link .nav-badge { flex-shrink: 0; }

/* The two ways out, quieter than the places in. */
.studio-exit {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 38px;
  padding: 0.35rem var(--space-3);
  background: none;
  border: 0;
  border-radius: var(--r-2);
  color: var(--text-3);
  font: inherit;
  font-size: var(--step--1);
  text-align: left;
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.studio-exit:hover {
  background: var(--ink-600);
  color: var(--text);
}

.studio-bar { display: none; }

@media (min-width: 1000px) {
  .admin--studio { grid-template-columns: 232px minmax(0, 1fr); }

  /* Fifteen places and two ways out are taller than a small laptop: the bar
     scrolls inside itself rather than losing «Sair» below the screen. */
  .admin--studio .admin__side {
    gap: 0;
    padding: var(--space-4) var(--space-3);
    overflow-y: auto;
    scrollbar-width: thin;
  }

  .admin--studio .admin__brand {
    margin: 0 0 var(--space-4);
    padding-inline: var(--space-3);
  }

  .studio-side .studio-nav__group + .studio-nav__group { margin-top: var(--space-4); }

  .studio-side .studio-nav__link { min-height: 36px; }

  .studio-side__foot {
    display: grid;
    gap: 2px;
    margin-top: auto;
    padding-top: var(--space-4);
  }

  .studio-side__foot form { margin: 0; }
}

/* Below 1000px, which is where Hugo reads it. A block rather than the grid:
   a sticky child of a grid row only sticks inside that row. */
@media (max-width: 999px) {
  .studio-bar {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 56px;
    padding: 0 clamp(1rem, 3vw, 2.5rem);
    background: var(--ink-900);
    border-bottom: 1px solid var(--line);
  }

  .studio-bar__brand {
    display: block;
    flex-shrink: 0;
  }

  .studio-bar__brand img {
    height: 28px;
    width: auto;
  }

  /* The page's name while its title is scrolled away. */
  .studio-bar__here {
    min-width: 0;
    padding-left: var(--space-3);
    border-left: 1px solid var(--line);
    overflow: hidden;
    color: var(--text-2);
    font-size: 0.875rem;
    font-weight: 500;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .studio-bar__tools {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
  }

  .studio-bar__tool {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    min-height: 44px;
    padding: 0 0.75rem;
    border: 1px solid transparent;
    border-radius: var(--r-2);
    color: var(--text-2);
    font-size: 0.875rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    list-style: none;
    transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
      color var(--fast) var(--ease);
  }

  .studio-bar__tool::-webkit-details-marker { display: none; }

  .studio-bar__tool svg { flex-shrink: 0; }

  .studio-bar__tool:hover {
    background: var(--ink-600);
    color: var(--text);
  }

  .studio-menu__toggle {
    border-color: var(--line-strong);
    color: var(--text);
  }

  .studio-menu[open] > .studio-menu__toggle {
    background: var(--ink-600);
    border-color: var(--text-3);
  }

  /* Everything behind the open sheet is dimmed, and pressing it closes the
     sheet: it is drawn by the toggle itself, so a press there is a press on
     «Menu». */
  .studio-menu[open] > .studio-menu__toggle::before {
    content: "";
    position: fixed;
    inset: 56px 0 0;
    background: rgba(10, 11, 18, 0.55);
    cursor: default;
  }

  .studio-menu__sheet {
    position: fixed;
    top: 56px;
    right: 0;
    left: 0;
    z-index: 1;
    max-height: calc(100vh - 56px);
    max-height: calc(100dvh - 56px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-5) clamp(1rem, 3vw, 2.5rem) var(--space-4);
    background: var(--ink-900);
    border-bottom: 1px solid var(--line-strong);
    box-shadow: var(--shadow-3);
  }

  .studio-menu__sheet .studio-nav {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-5);
  }

  .studio-menu__sheet .studio-nav__link { min-height: 44px; }

  .studio-menu__foot {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-5);
    padding-top: var(--space-3);
    border-top: 1px solid var(--line);
  }

  .studio-menu__foot form { margin: 0; }

  .studio-menu__foot .studio-exit {
    width: auto;
    min-height: 44px;
  }

}

/* Two groups a row on a phone: all fifteen places still fit one screen. */
@media (max-width: 699px) {
  .studio-menu__sheet .studio-nav {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5) var(--space-3);
  }

  .studio-menu__sheet .studio-nav__link { padding-inline: var(--space-2); }

  .studio-menu__sheet .studio-nav__heading { padding-inline: var(--space-2); }
}

/* On a phone «Mensagens» keeps its glyph and its count; the word is clipped,
   not removed, so a screen reader still says it. */
@media (max-width: 559px) {
  .studio-bar__word {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .studio-bar__tool .nav-badge {
    position: absolute;
    top: 4px;
    right: 2px;
    min-width: 1rem;
    height: 1rem;
    margin: 0;
    padding: 0 0.25rem;
    font-size: 0.625rem;
    line-height: 1rem;
  }

  .studio-menu__toggle .nav-badge {
    position: static;
    min-width: 1.25rem;
    height: 1.25rem;
    font-size: 0.6875rem;
    line-height: 1.25rem;
  }
}

/* --- «Avisos», at the top of every page --------------------------------------
   One quiet box rather than a heading floating over loose lines, so it reads
   as one thing that can be taken in and passed. */

.admin--studio .attention {
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.admin--studio .attention__heading { margin-bottom: var(--space-3); }

.admin--studio .attention__item { padding: var(--space-2) var(--space-3); }

/* --- Page head ----------------------------------------------------------------
   Title, at most one line under it, and the page's one main action. */

.admin__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.admin--studio .admin__lead {
  max-width: 72ch;
  color: var(--text-2);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* The way back to the page this one hangs from, in the words of its title. */
.admin--studio .admin__head .back-link {
  margin-bottom: var(--space-2);
  color: var(--text-2);
  font-size: var(--step--1);
  letter-spacing: 0;
  text-transform: none;
}

.admin--studio .admin__head .back-link:hover { color: var(--text); }

/* --- Section card ------------------------------------------------------------ */

.panel__link {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 500;
  white-space: nowrap;
  transition: color var(--fast) var(--ease);
}

.panel__link:hover { color: var(--text); }

.panel__lead {
  max-width: 72ch;
  margin: calc(var(--space-2) * -1) 0 var(--space-4);
  color: var(--text-3);
  font-size: var(--step--1);
  line-height: 1.5;
}

/* The end of a card: a hairline, then what is done less often — and what
   cannot be undone, which is never beside the button pressed every day. */
.panel__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.panel__foot p {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.panel__foot form { margin: 0; }

/* Cards side by side on a wide screen, one under the other on a phone. */
.panel-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: var(--space-5);
  margin-bottom: var(--space-5);
}

.panel-row > .panel { margin-bottom: 0; }

/* --- Data table ----------------------------------------------------------------
   Figures to the right, under a heading that is to the right as well: .table td
   outranks .table__num on its own, so a column of sizes and prices stood on the
   left. Not on a phone, where the stacked row reads left to right. */

@media (min-width: 701px) {
  .admin--studio .table .table__num { text-align: right; }
}

/* --- Badge ------------------------------------------------------------------- */

.badge--danger {
  background: var(--red-tint);
  color: var(--red-300);
}

/* --- Empty state ----------------------------------------------------------------
   Inside a card it needs less air than on a page of its own. */

.empty-state--compact {
  gap: var(--space-3);
  padding: var(--space-6) var(--space-4);
}

.empty-state--compact h2 { font-size: var(--step-1); }

.admin--studio .empty-state p {
  max-width: 46ch;
  margin: 0;
}

/* --- Disclosure for what is not needed every day -------------------------------- */

.more {
  margin-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.more--flush {
  margin-top: 0;
  border-top: 0;
}

.more > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  color: var(--text-2);
  font-size: 0.9375rem;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  transition: color var(--fast) var(--ease);
}

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

.more > summary::before {
  content: "";
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  margin: 0 0.35rem 0 0.15rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--fast) var(--ease);
}

.more[open] > summary::before { transform: rotate(45deg); }

.more > summary:hover { color: var(--text); }

.more__body { padding: var(--space-2) 0 var(--space-3); }

.more__body > :last-child { margin-bottom: 0; }

/* --- Save bar for a long form ------------------------------------------------------
   The last child of the <form>. It stays in sight at the bottom of the screen
   while the form scrolls past, and settles at the form's end. */

.save-bar {
  position: sticky;
  bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.save-bar__dirty {
  margin: 0 auto 0 0;
  color: var(--warn);
  font-size: var(--step--1);
  visibility: hidden;
}

.save-bar.is-dirty .save-bar__dirty { visibility: visible; }

/* --- «Para hoje»: what is waiting, one line each ------------------------------------ */

.todo {
  margin: 0;
  padding: 0;
  list-style: none;
}

.todo > li + li { border-top: 1px solid var(--line); }

.todo__main {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 52px;
  padding: var(--space-2) 0;
  color: var(--text);
}

.todo__count {
  flex-shrink: 0;
  min-width: 2.5rem;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--red-300);
}

.todo__count--warn { color: var(--warn); }

.todo__text {
  flex: 1 1 auto;
  min-width: 0;
}

.todo__main svg {
  flex-shrink: 0;
  color: var(--text-3);
  transition: transform var(--fast) var(--ease), color var(--fast) var(--ease);
}

.todo__main:hover .todo__text {
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

.todo__main:hover svg {
  color: var(--text);
  transform: translateX(2px);
}

/* The requests themselves, under their line, lined up with its words. */
.todo__items {
  display: grid;
  gap: 2px;
  margin: calc(var(--space-1) * -1) 0 var(--space-3) calc(2.5rem + var(--space-3));
  padding: 0;
  list-style: none;
}

.todo__items a {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.75rem;
  padding: 0.3rem 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.todo__items a:hover { color: var(--text); }

.todo__items strong {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  .todo__items { margin-left: 0; }
}

/* Figures that are only there to be read. */
.stats--compact {
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  margin-bottom: var(--space-5);
}

.stats--compact .stat { padding: var(--space-4); }

.stats--compact .stat__value { font-size: 1.5rem; }

/* --- The pages this block belongs to -------------------------------------------- */

/* Resumo: the day's list first, and nothing left to say is said in one line. */
.today__none {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin: 0;
  color: var(--text-2);
}

/* Armazenamento: a check that found nothing says so in green, and the albums
   with nothing on the server are a plain list of names. */
.repair__item--ok {
  border-color: rgba(111, 195, 160, 0.45);
  background: var(--ok-tint);
}

.storage-empty {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding-left: 0;
  list-style: none;
  font-size: var(--step--1);
}

.storage-empty li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Acesso às mensagens: the three states share one card. */
.inbox-access__steps { max-width: 40rem; }

.inbox-access .detail-list { margin: 0; }

/* Long work a request at a time: the line that moves is the one to read. */
.continue [role='status'] {
  color: var(--text);
  font-size: var(--step-1);
}

@media (max-width: 700px) {
  .admin--studio .continue__actions .btn { min-height: 44px; }
}

/* =========================================================================
   Albums (admin/albums.php, admin/album-detail.php): the list, and one album
   laid out in the order the work on it is done — what is in it, who sees it,
   the envelopes, then its settings and archiving folded away at the end.
   Everything here is the photographer's panel only.
   ========================================================================= */

/* --- The list ---------------------------------------------------------------- */

/* A new album on one row at 900px: the name takes the room, the date and the
   note beside it, the button at the end. One under the other on a phone. */
.album-new__form {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(9.5rem, 1fr) minmax(0, 1.4fr) auto;
  align-items: end;
  gap: var(--space-4);
}

.album-new__form .field { margin-bottom: 0; }

/* The same height as the fields beside it; a date field draws itself taller. */
.album-new__form .field__control,
.album-new__form .btn {
  height: 52px;
  min-height: 52px;
}

@media (max-width: 760px) {
  .album-new__form { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  .album-new__title,
  .album-new__form .btn { grid-column: 1 / -1; }
}

@media (max-width: 480px) {
  .album-new__form { grid-template-columns: minmax(0, 1fr); }
}

/* The list's title, how many, and the search and order beside them. */
.album-list__head { align-items: center; }

.album-list__count {
  margin-left: 0.35rem;
  color: var(--text-3);
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 400;
}

.album-list__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Beside the order, not over it: the panel's own rule below 1000px gives a
   search box the whole row. */
.album-list__tools .toolbar__search { flex: 1 1 13rem; }

.album-list__tools .toolbar__search input {
  width: 100%;
  max-width: none;
}

.album-list__sort {
  width: auto;
  flex: 0 0 auto;
  border-radius: var(--r-full);
}

.album-list__name {
  color: var(--text);
  text-decoration: none;
}

.album-list__name:hover {
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

.album-list__note,
.album-list__more {
  display: block;
  margin-top: 2px;
  color: var(--text-3);
  font-size: var(--step--1);
  font-weight: 400;
}

.album-list__nobody { color: var(--text-3); }

.album-list__who { white-space: nowrap; }

.album-list__badges {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.album-list__badges .badge { white-space: nowrap; }

@media (max-width: 700px) {
  .album-list__tools { flex: 1 1 100%; }

  .album-list__sort { min-height: 44px; }

  .album-list__tools .toolbar__search { min-height: 44px; }

  /* A row read left to right: the count, then what goes with it. */
  .table--albums .album-list__more {
    display: inline;
    margin-left: 0.35em;
  }
}

/* A card's one line when there is nothing in it yet. */
.album-none {
  margin: 0 0 var(--space-2);
  color: var(--text-2);
}

/* --- One album: the head ------------------------------------------------------- */

/* Public or private first, then the date and the counts, a dot between. */
.album-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

.album-facts__item + .album-facts__item::before,
.album-counts > * + *::before {
  content: "\00B7";
  display: inline-block;
  margin-right: var(--space-2);
  color: var(--text-3);
}

@media (max-width: 700px) {
  .album-facts { justify-content: center; }
}

/* Archived: the sentence, and the one way on at its end. */
/* «A preparar as fotografias para as famílias» (FamilyCopies): a quiet line
   with its progress, under the album's head while the copies are made. */
.album-prepare {
  display: grid;
  gap: 0.35rem;
  margin: 0 0 var(--space-4);
  padding: 0.75rem 1rem;
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.album-prepare__bar {
  display: block;
  height: 4px;
  overflow: hidden;
  background: var(--ink-600);
  border-radius: 999px;
}

.album-prepare__bar > span {
  display: block;
  height: 100%;
  background: var(--red-500);
  border-radius: inherit;
  transition: width var(--slow) var(--ease);
}

.album-prepare__text {
  margin: 0;
  font-weight: 600;
}

.album-prepare__hint {
  margin: 0;
  color: var(--text-3);
}

.album-archived {
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}

.album-archived p {
  flex: 1 1 22rem;
  margin: 0;
}

/* --- Photographs and videos ------------------------------------------------------ */

.album-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-2);
}

/* «12 por rever», and beside it the way through them one after another. */
.album-counts__review {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

.album-review {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 30px;
  padding: 0 0.6rem;
  border: 1px solid rgba(224, 177, 94, 0.45);
  border-radius: var(--r-2);
  color: var(--warn);
  font-size: 0.8125rem;
  font-weight: 600;
  transition: background var(--fast) var(--ease);
}

.album-review:hover { background: var(--warn-tint); }

/* Smaller tiles than the photographs page: this grid is for choosing, and it
   draws every photograph of the album or sub-album, so a match of hundreds
   stays a grid to run the eye down. Never more than six to a row. */
.order-list--album {
  grid-template-columns: repeat(auto-fill, minmax(max(112px, calc((100% - 5 * var(--space-2)) / 6)), 1fr));
  gap: var(--space-2);
}

.order-list--album .order-item { cursor: pointer; }

/* An album tile's words (Arquivada, Destaque, Por rever) along the bottom
   edge, one above the other: at the top they ran under the tick on a tile
   a phone makes a third of its width. */
.order-item__badges {
  position: absolute;
  left: 4px;
  bottom: 4px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  pointer-events: none;
}

@media (max-width: 560px) {
  .order-list--album { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* Two words stacked on a third of a phone still clear the tick. */
  .admin--studio .order-item__badges .badge {
    padding: 0.15rem 0.4rem;
    font-size: 0.625rem;
    line-height: 1.25;
  }
}

.album-picks__hint {
  margin: 0 0 var(--space-3);
  color: var(--text-3);
}

.album-picks > .album-picks__hint { margin: var(--space-4) 0 0; }

.album-picks > .album-picks__hint + .album-actions { margin-top: var(--space-2); }

.album-actions--flush { margin-top: 0; }

/* The films, under the photographs with a hairline between. */
.album-films {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.album-films__title {
  margin: 0 0 var(--space-3);
  font-size: var(--step-0);
}

.album-films__hint { margin: 0 0 var(--space-3); }

.album-films .more__body > .film-upload {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* --- Who sees it -------------------------------------------------------------------- */

.album-who td .badge { margin-left: 0.25rem; }

.album-who__line {
  display: block;
  margin-top: 2px;
  color: var(--text-3);
  font-size: var(--step--1);
  font-weight: 400;
  overflow-wrap: anywhere;
}

.album-who .table__line .tiny { margin-left: 0.5rem; }

.album-who__foot { margin: var(--space-4) 0 0; }

/* --- Envelopes: two figures and the way to their own screen ------------------------------ */

.album-envelopes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.album-envelopes .album-none { margin: 0; }

.album-envelopes__facts {
  display: flex;
  gap: var(--space-6);
  margin: 0;
}

.album-envelopes__facts dt {
  color: var(--text-3);
  font-size: var(--step--1);
}

.album-envelopes__facts dd {
  margin: 2px 0 0;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

/* --- Cards that fold: «Definições», «Arquivar ou eliminar», and the clubs' ----------------
   The heading is the whole handle, with what is inside said beside it and the
   chevron at the far end — the same one the smaller disclosures use. */

.panel--fold > summary,
.admin--studio .club-panel > summary {
  justify-content: flex-start;
  align-items: center;
  gap: var(--space-1) var(--space-3);
  min-height: 44px;
  list-style: none;
  cursor: pointer;
}

.panel--fold > summary::-webkit-details-marker { display: none; }

.panel--fold > summary::after,
.admin--studio .club-panel > summary::after {
  content: "";
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin: 0 0.3rem 0 auto;
  border-right: 1.5px solid var(--text-3);
  border-bottom: 1.5px solid var(--text-3);
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}

.panel--fold[open] > summary::after,
.admin--studio .club-panel[open] > summary::after { transform: rotate(-135deg); }

.admin--studio .club-panel > summary h2::after { content: none; }

.panel--fold:not([open]) > summary { margin-bottom: 0; }

.panel--fold > summary:hover::after,
.admin--studio .club-panel > summary:hover::after { border-color: var(--text); }

.fold__meta {
  color: var(--text-3);
  font-size: var(--step--1);
}

/* On a phone the title and what is inside go one under the other, and the
   chevron stays level with the title rather than dropping to a line of its own. */
@media (max-width: 700px) {
  .panel--fold > summary,
  .admin--studio .club-panel > summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    justify-items: start;
  }

  .panel--fold > summary > *,
  .admin--studio .club-panel > summary > * { grid-column: 1; }

  .panel--fold > summary::after,
  .admin--studio .club-panel > summary::after {
    grid-column: 2;
    grid-row: 1;
    margin: 0 0.3rem;
  }
}

/* --- Settings ------------------------------------------------------------------------------ */

.album-settings__title {
  margin: var(--space-6) 0 var(--space-3);
  padding: var(--space-5) 0 0;
  border-top: 1px solid var(--line);
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--text);
}

/* The name has the room; the date and the price beside it. */
.album-settings__basics { grid-template-columns: minmax(0, 2fr) minmax(9.5rem, 1fr) minmax(0, 1fr); }

/* «Traduções» on the album's settings (migration 034): folded under the
   Portuguese fields, opened by itself once something is written in it. */
.album-translations {
  margin-top: var(--space-5);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.album-translations > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--text);
}

.album-translations[open] > summary { margin-bottom: var(--space-2); }

.album-translations .form-grid {
  /* One line a language: the name, then its description beside it. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  margin-top: var(--space-4);
}

@media (max-width: 640px) {
  .album-translations .form-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 700px) {
  .album-settings__basics { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  .album-settings__name { grid-column: 1 / -1; }
}

@media (max-width: 480px) {
  .album-settings__basics { grid-template-columns: minmax(0, 1fr); }
}

.album-settings__group {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* A legend drawn like the other group titles: floated, it is an ordinary
   block, not a gap cut into a border. */
.album-settings__group > legend {
  float: left;
  width: 100%;
}

.album-settings__group > legend + * { clear: both; }

.album-settings__choice {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-bottom: var(--space-3);
}

.album-settings__choice input { margin-top: 0.3rem; }

.album-settings__choice .field__hint { display: block; }

.album-settings__grant { margin: var(--space-4) 0 0; }

.album-settings__grant .switch { align-items: flex-start; }

.album-settings__grant .field__hint {
  display: block;
  margin-top: 2px;
}


/* =========================================================================
   Sub-albums, the selection bar and envelopes per sub-album
   (admin/album-detail.php, admin/envelopes.php, admin/albums.php, and the
   redeem form in client/albums.php). A person's sub-album is the album's
   photographs they are in; the strip over the grid chooses one, the bar at
   its foot acts on what is ticked. Selected is a whole border or a filled
   ground, never a line down one side.
   ========================================================================= */

/* --- The album's reference, in the head -------------------------------------- */

.album-facts__ref strong {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--text);
}

.album-list__ref { font-variant-numeric: tabular-nums; }

.album-settings__reference { max-width: 18rem; }

.album-settings__reference .field__control {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* --- The strip of sub-albums ---------------------------------------------------- */

.subalbums { margin: var(--space-4) 0; }

.subalbums__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-1) var(--space-4);
}

.subalbums__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: 600;
}

.subalbums__links {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  font-size: var(--step--1);
}

.subalbums__lead {
  margin: var(--space-1) 0 var(--space-3);
  color: var(--text-3);
}

.subalbums__strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.subalbum-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 36px;
  padding: 0.3rem 0.85rem;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: 0.875rem;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.subalbum-chip:hover {
  border-color: var(--text-3);
  color: var(--text);
}

.subalbum-chip:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.subalbum-chip__count {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.subalbum-chip.is-empty { color: var(--text-3); }

/* The one shown: a filled ground, its whole edge the same colour. */
.subalbum-chip.is-current {
  background: var(--text);
  border-color: var(--text);
  color: var(--ink-900);
}

.subalbum-chip.is-current .subalbum-chip__count { color: var(--ink-500); }

/* «Adicionar pessoa»: a way to make one, not one of them. */
.subalbum-chip--add {
  border-style: dashed;
  color: var(--text-3);
  list-style: none;
}

.subalbum-chip--add::-webkit-details-marker { display: none; }

.subalbums__add { position: relative; }

.subalbums__add[open] > .subalbum-chip--add {
  border-style: solid;
  border-color: var(--text-3);
  color: var(--text);
}

.subalbums__pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 25;
  display: grid;
  gap: var(--space-3);
  width: min(19rem, calc(100vw - 2rem));
  padding: var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.subalbums__add.is-flipped .subalbums__pop {
  right: 0;
  left: auto;
}

.subalbums__pop .field { margin: 0; }

.subalbums__pop .btn { justify-self: start; }

/* Whose sub-album, which family, and the envelope — with the way to print it. */
.subalbum-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.subalbum-head__text {
  flex: 1 1 22rem;
  min-width: 0;
}

.subalbum-head__who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-2);
  margin: 0;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.subalbum-head__who strong {
  color: var(--text);
  font-size: var(--step-0);
}

.subalbum-head__who > * + *::before {
  content: "\00B7";
  margin-right: var(--space-2);
  color: var(--text-3);
}

/* The family, then the envelope: a line each, so nothing starts with a dot. */
.subalbum-head__meta {
  display: grid;
  gap: 1px;
  margin: 2px 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.subalbum-head__print { margin: 0; }

.subalbum-note { margin: var(--space-3) 0 0; }

.subalbum-empty { margin: var(--space-2) 0 var(--space-4); }

/* The tick on each tile: a little larger, and a thumb's reach around it. */
.order-list--album .order-item__check {
  width: 26px;
  height: 26px;
}

.order-list--album .order-item__check::after {
  content: "";
  position: absolute;
  inset: -9px;
}

.order-list--album .order-item--pick:focus-within {
  outline: 2px solid var(--blue);
  outline-offset: -2px;
}

.order-list--album .order-item--pick:has(input:checked) {
  outline: 2px solid var(--red-500);
  outline-offset: -2px;
}

/* --- The selection bar ------------------------------------------------------------
   Out of the way until something is ticked; then it rises at the foot of the
   screen and stays there while the grid scrolls (sticky inside the form, so it
   never covers what comes after the grid). Without script the ticks alone
   bring it (:has), and each button is an ordinary submit. */

.select-bar {
  position: sticky;
  bottom: var(--space-3);
  z-index: 30;
  display: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-4);
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-4);
  box-shadow: var(--shadow-3);
}

.album-picks:has(input[data-select]:checked) .select-bar,
.select-bar.is-visible {
  display: flex;
  animation: select-bar-in var(--base) var(--ease);
}

@keyframes select-bar-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .album-picks:has(input[data-select]:checked) .select-bar,
  .select-bar.is-visible { animation: none; }
}

.select-bar__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--space-3);
}

.select-bar__clear { gap: 0.3rem; }

/* Below 1000px the panel's places are a bar along the foot of the screen:
   the selection bar rises above it. */
@media (max-width: 999px) {
  .select-bar { bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-2)); }
}

.select-bar__count {
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
}

.select-bar__all {
  min-height: 32px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text-2);
  font: inherit;
  font-size: 0.9375rem;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
  cursor: pointer;
}

.select-bar__all:hover { color: var(--text); }

.select-bar__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
}

.select-bar__menu { position: relative; }

.select-bar__menu > summary { list-style: none; }

.select-bar__menu > summary::-webkit-details-marker { display: none; }

.select-bar__menu[open] > summary {
  background: var(--ink-500);
  border-color: var(--text-3);
}

/* What «Adicionar a subálbum…» and «Mais» open: over the bar, not under it. */
.select-bar__pop {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  z-index: 31;
  display: grid;
  gap: var(--space-3);
  width: min(19rem, calc(100vw - 2rem));
  max-height: min(60vh, 28rem);
  overflow-y: auto;
  padding: var(--space-4);
  background: var(--ink-700);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.select-bar__pop--end,
.select-bar__menu.is-flipped .select-bar__pop {
  right: 0;
  left: auto;
}

.select-bar__pop-title {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.select-bar__pop .field__label { margin: 0; }

.select-bar__pop .btn { justify-self: start; }

.select-bar__people {
  display: grid;
  gap: 2px;
}

.select-bar__person {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 40px;
  padding: 0 var(--space-2);
  border-radius: var(--r-2);
  cursor: pointer;
}

.select-bar__person:hover,
.select-bar__person:has(input:checked) { background: var(--ink-600); }

.select-bar__person input { accent-color: var(--red-500); }

.select-bar__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.select-bar__row .field__control {
  flex: 1 1 10rem;
  min-width: 0;
}

.select-bar__row--danger {
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

/* --- The envelopes page ----------------------------------------------------------- */

/* The album's reference beside the title: what every envelope carries. */
.envelope-ref {
  display: grid;
  gap: 0.1rem;
  margin: 0;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
}

.envelope-ref span {
  color: var(--text-3);
  font-size: var(--step--1);
}

.envelope-ref strong {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.25rem;
  letter-spacing: 0.06em;
}

/* The tick that chooses a row for «Imprimir os escolhidos», before its name. */
.envelope-table__who {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.envelope-table__who input {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 0.2rem;
  accent-color: var(--red-500);
}

.envelope-table__waiting {
  display: block;
  color: var(--text-3);
}

.envelope-table__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
}

.envelope-table__actions form { margin: 0; }

.envelope-chosen { margin-top: var(--space-4); }

.envelope-whole { max-width: 32rem; }

.envelope-whole__made {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
  padding: var(--space-4) 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
}

.envelope-whole__made li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.envelope-whole__made li > span {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-3);
  align-items: baseline;
}

.envelope-whole__made form { margin: 0; }

/* --- Envelopes that keep their code (migration 031) ------------------------------ */

/* «Criar» and «Imprimir», side by side where there is room, one under the
   other on a phone. Each a plain box of its own, as a sub-album's head is. */
.envelope-steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-4);
  margin-top: var(--space-4);
}

.envelope-step {
  min-width: 0;
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.envelope-step__title {
  margin: 0 0 var(--space-1);
  font-size: var(--step-0);
}

.envelope-step__says {
  margin: 0;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.envelope-step__left-out { margin: var(--space-2) 0 0; }

.envelope-step .envelope-go { margin-top: var(--space-4); }

.envelope-step .envelope-free { margin-top: var(--space-3); }

/* A live envelope's code, as the sheet prints it, under its state. */
.envelope-code {
  display: block;
  margin-top: 2px;
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.envelope-code--none {
  color: var(--warn);
  font-family: inherit;
  font-size: var(--step--1);
  letter-spacing: 0;
  white-space: normal;
}

/* «Vai por envelope»: a switch that is a button, so it needs no script. */
.delivery-switch-form {
  display: flex;
  align-items: center;
  margin: 0;
}

.delivery-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 36px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text-2);
  font: inherit;
  font-size: var(--step--1);
  text-align: left;
  cursor: pointer;
}

.delivery-switch:hover { color: var(--text); }

.delivery-switch > span:last-child { white-space: nowrap; }

/* Five columns on the envelopes table: the name keeps room to be read. */
.envelope-table td:first-child { min-width: 10rem; }

.delivery-switch[aria-checked="true"] .switch__track {
  background: var(--red-500);
  border-color: var(--red-500);
}

.delivery-switch[aria-checked="true"] .switch__track::after {
  background: #fff;
  transform: translateX(16px);
}

.delivery-switch:focus-visible { outline: none; }

.delivery-switch:focus-visible .switch__track {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* The ticked rows: what is done to them, in one row of buttons. */
.envelope-chosen__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.envelope-chosen__lead {
  margin-right: var(--space-1);
  color: var(--text-2);
  font-size: var(--step--1);
}

.envelope-chosen__note { margin: var(--space-2) 0 0; }

/* The key is missing or was changed: the sentence, and the one way on. */
.envelope-key {
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}

.envelope-key p {
  flex: 1 1 22rem;
  margin: 0;
}

.envelope-key form { margin: 0; }

.envelope-whole__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.envelope-whole__made .envelope-code { display: inline; }

@media (max-width: 700px) {
  .envelope-steps { grid-template-columns: 1fr; }

  .envelope-step { padding: var(--space-3); }

  .delivery-switch { min-height: 44px; }

  .envelope-chosen__lead { flex-basis: 100%; }
}

/* --- The families' own «Tens um envelope?»: the reference, then the code ------------ */

.redeem-form .redeem-form__reference { max-width: 12rem; }

/* The reference, the code and the button share one line and one height, the
   button's: a 52px box beside a 38px button looked like two rows. */
.redeem-form { align-items: stretch; }

.redeem-form .field__control,
.redeem-form .btn {
  min-height: 44px;
  height: 44px;
}

.redeem-form .field__control {
  padding: 0 0.85rem;
  font-size: 0.9375rem;
}

/* --- Phones -------------------------------------------------------------------------- */

@media (max-width: 700px) {
  /* The reference last in the head, and on a line of its own: a dot at the
     start of a wrapped line reads as a stray mark. */
  .album-facts .album-facts__ref {
    flex-basis: 100%;
    text-align: center;
  }

  .album-facts .album-facts__ref::before { content: none; }

  /* The strip is one row that slides sideways, as the photographs page's
     piles do, and «Adicionar pessoa» opens as a sheet at the foot. */
  .subalbums__strip {
    flex-wrap: nowrap;
    margin-inline: calc(-1 * clamp(1.25rem, 2.5vw, 1.75rem));
    padding: 2px clamp(1.25rem, 2.5vw, 1.75rem) var(--space-2);
    overflow-x: auto;
    scrollbar-width: none;
  }

  .subalbums__strip::-webkit-scrollbar { display: none; }

  .subalbum-chip { min-height: 40px; }

  /* A sheet at the foot of the screen, over the places' bar. */
  .subalbums__pop,
  .select-bar__pop {
    position: fixed;
    top: auto;
    right: var(--space-3);
    bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3));
    left: var(--space-3);
    z-index: 95;
    width: auto;
    max-height: 60vh;
  }

  .subalbum-head { padding: var(--space-3); }

  /* Two rows: how many and «Limpar»; then the actions, one row that slides
     sideways rather than four rows over the grid. */
  .select-bar { padding: var(--space-2); }

  .select-bar__lead {
    flex: 1 1 100%;
    flex-wrap: nowrap;
    padding-left: var(--space-2);
  }

  /* The bar takes the card's whole width here, and «Limpar» is its cross
     alone (the word stays for a screen reader), so the count and «Selecionar
     todas» keep one line. */
  .select-bar { margin-inline: calc(-1 * clamp(1.25rem, 2.5vw, 1.75rem) + var(--space-2)); }

  .select-bar__all { white-space: nowrap; }

  .select-bar__clear {
    width: 44px;
    margin-left: auto;
    padding: 0;
    justify-content: center;
  }

  .select-bar__clear-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .select-bar__actions {
    flex: 1 1 100%;
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .select-bar__actions::-webkit-scrollbar { display: none; }

  .select-bar__actions > * { flex-shrink: 0; }

  .select-bar .btn {
    min-height: 44px;
    white-space: nowrap;
  }

  .envelope-ref { justify-self: start; }

  /* A row's «Imprimir» and «Anular» on a line of their own, under the
     person and the envelope, rather than squeezing the name beside them. */
  .table--stack.envelope-table td:last-child,
  .table--stack.envelope-table td:last-child:has(.btn) {
    order: 0;
    flex: 1 0 100%;
    margin-left: 0;
  }

  .envelope-table__actions { justify-content: flex-start; }

  .redeem-form .redeem-form__reference { max-width: none; }
}
/* =========================================================================
   Clientes, Clubes, Marcações e Encomendas (admin/clients.php,
   client-detail.php, clubs.php, club-detail.php, bookings.php,
   booking-detail.php, orders.php, order-detail.php). Built on the panel's
   pieces above; only what these pages need besides. Every class here is the
   photographer's panel's alone.
   ========================================================================= */

/* A section a link or the head's button points at is not hidden under the
   sticky bar the panel has below 1000px. */
.admin--studio .setting,
.admin--studio .req,
.admin--studio #responder,
.admin--studio #novo-cliente,
.admin--studio #novo-clube { scroll-margin-top: 5rem; }

/* --- A list with a search box over it --------------------------------------- */

.list-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

.list-search__field {
  position: relative;
  flex: 1 1 16rem;
  min-width: 0;
}

.list-search__field svg {
  position: absolute;
  top: 50%;
  left: 0.9rem;
  color: var(--text-3);
  transform: translateY(-50%);
  pointer-events: none;
}

.list-search__field .field__control {
  min-height: 44px;
  padding-block: 0.55rem;
  padding-left: 2.5rem;
}

.list-search__count {
  color: var(--text-3);
  font-size: var(--step--1);
}

.list-search__none { margin: var(--space-4) 0 0; }

/* A stacked row is display: flex on a phone, which outranks [hidden]. */
.admin--studio [data-search-row][hidden] { display: none; }

/* --- A few quiet states under a name or an address ---------------------------- */

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.4rem 0 0;
}

.badges:empty { display: none; }

/* A long club name ends in «…» rather than folding its pill in two. */
.badges .badge {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.badge--link { transition: color var(--fast) var(--ease); }
.badge--link:hover { color: var(--text); }

.when--ok { color: var(--ok); }
.when--warn { color: var(--warn); }
.when--danger { color: var(--red-300); }

/* --- Clientes and Clubes: the lists ------------------------------------------- */

.client-table__name { color: var(--text); }

.client-table__name:hover strong {
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

.client-table__seen .tiny,
.client-table__seen .badge {
  display: block;
  width: fit-content;
  margin-top: 0.2rem;
}

.client-table__seen .badge { white-space: nowrap; }

@media (max-width: 700px) {
  .client-table__seen .tiny,
  .client-table__seen .badge { display: inline-flex; margin: 0 0 0 0.35rem; }
}

.client-new__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.client-new__cards,
.club-new + .field__hint { margin: var(--space-4) 0 0; }

/* One-line forms on these pages: the box and its button the same height. */
.club-new .field__control,
.club-add .field__control,
.setting .inline-form .field__control {
  min-height: 44px;
  padding-block: 0.55rem;
}

.club-new .btn,
.club-add .btn,
.setting .inline-form .btn,
.client-discount .btn { min-height: 44px; }

/* --- A client's page ------------------------------------------------------------ */

.client-head { align-items: flex-start; }

.client-head__who { min-width: 0; }

.client-head__name {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.client-head__name > div { min-width: 0; }
.client-head__name h1 { overflow-wrap: anywhere; }
.client-head__name .avatar { margin-top: 0.1rem; }

.client-head__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem var(--space-4);
  margin: var(--space-2) 0 0;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.client-head__email { overflow-wrap: anywhere; }

/* On a phone the picture, the name and what is said of them are one column
   down the middle, as the panel's other heads are. */
@media (max-width: 700px) {
  .client-head__name {
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    text-align: center;
  }

  .client-head__facts,
  .client-head .badges,
  .client-head .admin__actions { justify-content: center; }
}

.client-off {
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
}

.client-off form { margin: 0; }

.client-album__scope {
  display: block;
  margin-top: 0.15rem;
}

.client-albums__clubs {
  margin: var(--space-4) 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

/* Orders and sessions: a line each, the whole line the way to its page. */
.mini-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.mini-list li + li { border-top: 1px solid var(--line); }

.mini-list a {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  min-height: 48px;
  padding: var(--space-2) 0;
  color: var(--text);
}

.mini-list a:hover strong {
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

.mini-list__main {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.6rem;
  min-width: 0;
}

.mini-list__side {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-left: auto;
}

.mini-list__amount {
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* Conta e segurança: each line a state, and its remedy beside it. */
.settings {
  margin: 0;
  padding: 0;
  list-style: none;
}

.setting {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) 0;
}

.setting:first-child { padding-top: 0; }
.setting:last-child { padding-bottom: 0; }
.setting + .setting { border-top: 1px solid var(--line); }

.setting__text {
  display: grid;
  flex: 1 1 18rem;
  gap: 0.2rem;
  min-width: 0;
}

.setting__text strong { font-weight: 600; }
.setting__value { overflow-wrap: anywhere; }

.setting__note {
  color: var(--text-3);
  font-size: var(--step--1);
}

.setting__action { margin: 0; }

.setting__wide {
  flex: 1 1 100%;
  margin: 0;
}

.setting .more.setting__wide {
  margin-top: calc(var(--space-2) * -1);
  border-top: 0;
}

.setting .alert { margin: 0; }

.client-discount .field__label { margin: 0; }

.client-discount__field {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-2);
}

.inline-form .client-discount__field .field__control {
  flex: none;
  width: 6.5rem;
  min-height: 44px;
  padding-block: 0.55rem;
}

.client-end__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.client-end__row p {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.client-end__row form { margin: 0; }

/* The foot of a card that holds nothing else: no rule above it. */
.panel__foot--alone {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* --- Clubes: one club ----------------------------------------------------------- */

.club-members__none { margin: 0; }

/* --- Marcações and Encomendas: the list, like an inbox ---------------------------- */

.req-group__count {
  margin-left: 0.35rem;
  color: var(--text-3);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* Who and what, then the sum, then the next step, on one line at 900px; the
   rows share their columns, so the sums stand in one column whatever the
   button beside them says. */
.req-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  column-gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.req {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
  row-gap: var(--space-2);
  padding: var(--space-3) 0;
}

.req:first-child { padding-top: 0; }
.req:last-child { padding-bottom: 0; }
.req + .req { border-top: 1px solid var(--line); }

/* Arrived at from Resumo: the one it was about is lit. A shadow, not a
   margin, so the row keeps the columns it shares. */
.req:target {
  background: var(--ink-600);
  box-shadow: 0 0 0 var(--space-3) var(--ink-600);
}

.req__main {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
  color: var(--text);
}

/* An open request: the row's link, and under it the number to ring, a link
   of its own (one link cannot hold another). Only as wide as its text, so a
   tap beside the number opens the request, not the phone. */
.req__who {
  display: grid;
  justify-items: start;
  gap: 0.2rem;
  min-width: 0;
}

.req__tel {
  color: var(--text-2);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
}

.req__tel:hover { color: var(--text); }

.req__tel--none {
  color: var(--text-3);
  text-decoration: none;
}

.req__main:hover .req__title strong {
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
}

.req__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
}

.req__title strong { font-weight: 600; }

.req__title span,
.req__meta strong { color: var(--text-2); }

.req__title span { font-size: var(--step--1); }

.req__meta {
  color: var(--text-3);
  font-size: var(--step--1);
  overflow-wrap: anywhere;
}

.req__meta strong {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.req__warn {
  color: var(--warn);
  font-size: var(--step--1);
}

.req__amount {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.req__action {
  display: flex;
  justify-content: flex-end;
}

/* «Anteriores», closed, is one line: not a card's worth of air around it. */
.req-group--past { padding-block: var(--space-2); }

.req__action form { margin: 0; }

.req--past .req__title strong { color: var(--text-2); }

/* On a phone: who and what across the top, the sum and the step under it. */
@media (max-width: 560px) {
  .req-list { grid-template-columns: minmax(0, 1fr) auto; }
  .req__main,
  .req__who { grid-column: 1 / -1; }
  /* A thumb's worth to tap, without moving the row. */
  .req__tel { padding-block: 0.6rem; margin-block: -0.6rem; }
  .req__amount { text-align: left; }
  .req__action .btn { min-height: 44px; }
}

/* --- A request's own page ----------------------------------------------------------- */

.req-head__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.req-facts dd { overflow-wrap: anywhere; }

.req-note { margin: var(--space-5) 0 0; }

.req-note figcaption {
  margin-bottom: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.req-note blockquote {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text);
}

.req-note + .booking__reply,
.req-facts + .booking__reply { margin-top: var(--space-4); }

/* The answer is the whole card here, not the end of a longer one. A sum or
   a day takes a third of the row, not all of it. */
.req-answer .booking__when { grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); }

.booking__answer.req-answer {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.booking__actions.req-next { margin-top: 0; }

@media (max-width: 700px) {
  .booking__answer.req-answer .booking__actions .btn,
  .booking__actions.req-next .btn { min-height: 44px; }
}

/* =========================================================================
   Fotografias e media: admin/photos, import, import-batch, categories,
   videos and site-images. Built from the panel's pieces above; these rules
   are only for classes these six pages alone use.
   ========================================================================= */

/* --- Fotografias: one toolbar over the list ---------------------------------
   Which import (right after one), the piles, and the narrowing sit in one
   card; the line under it says how many and becomes the selection bar. */

.library-bar {
  display: grid;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.library-bar:has(+ .library-status) {
  margin-bottom: 0;
  border-radius: var(--r-3) var(--r-3) 0 0;
}

.library-bar__batch {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-1) 0 var(--space-3);
  border-bottom: 1px solid var(--line);
}

.library-bar__batch p {
  margin: 0;
  font-weight: 600;
}

/* The piles: words with their count beside them, and the one being looked at
   underlined in red, as the menu marks where you are. */
.library-tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}

.library-tab {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 40px;
  padding: 0 0.8rem;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: 0.9375rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease),
    border-color var(--fast) var(--ease);
}

.library-tab::-webkit-details-marker { display: none; }

.library-tab:hover {
  background: var(--ink-600);
  color: var(--text);
}

/* The pile on show: a darker ground inside a whole border, no line under it. */
.library-tab[aria-current='true'] {
  border-color: var(--line-strong);
  background: var(--ink-800);
  color: var(--text);
  font-weight: 600;
}

.library-tab__count {
  color: var(--text-3);
  font-size: 0.8125rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.library-tab__count--warn { color: var(--warn); }

/* «Mais»: the rarer piles, in a list that drops from it. It opens to the
   right of its button, or to the left (.is-flipped, app.js) when the screen
   ends first. */
.library-more { position: relative; }

.library-more__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin: -3px 0 0 0.1rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}

.library-more[open] > .library-more__toggle {
  background: var(--ink-600);
  color: var(--text);
}

.library-more[open] > .library-more__toggle::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

.library-more__menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  display: grid;
  gap: 2px;
  min-width: 15rem;
  padding: var(--space-1);
  background: var(--ink-900);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.library-more__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 40px;
  padding: 0 var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: 0.9375rem;
  white-space: nowrap;
}

.library-more__item:hover {
  background: var(--ink-600);
  color: var(--text);
}

.library-more__item[aria-current='true'] {
  border-color: var(--line-strong);
  background: var(--ink-700);
  color: var(--text);
  font-weight: 600;
}

/* The narrowing: a word, a category, an album, the days, and «Filtrar». */
.library-refine {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.library-refine .control {
  width: auto;
  max-width: 16rem;
  min-height: 40px;
}

.library-refine__search {
  display: flex;
  flex: 1 1 12rem;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  min-height: 40px;
  padding: 0 0.75rem;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-3);
}

.library-refine__search:focus-within {
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

.library-refine__search input {
  flex: 1;
  width: 100%;
  min-width: 0;
  background: none;
  border: 0;
  outline: none;
  color: var(--text);
  font-size: var(--step--1);
}

.library-refine__go {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* «Por rever»: one line on what to do, the rest behind «Como funciona». */
.library-bar__note {
  display: grid;
  gap: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.library-bar__note > p {
  margin: 0;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.library-bar__note .alert { margin: 0; }

.library-bar__note > .library-bar__go { font-size: inherit; }

.library-bar__note .more {
  margin-top: 0;
  border-top: 0;
}

/* The days, asked for now and then: a button that says the range once one is
   set, and opens the two fields under it. Closed, their values still go. */
.library-dates { position: relative; }

.library-dates__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 40px;
  padding: 0 0.75rem;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
}

.library-dates__toggle::-webkit-details-marker { display: none; }

.library-dates__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin: -3px 0 0 0.1rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.library-dates.is-set > .library-dates__toggle {
  border-color: var(--line-strong);
  color: var(--text);
}

.library-dates__fields {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2) var(--space-3);
  width: max-content;
  padding: var(--space-3);
  background: var(--ink-900);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.library-dates__fields .control {
  max-width: none;
  color-scheme: dark;
}

.is-flipped > .library-more__menu,
.is-flipped > .library-dates__fields {
  right: 0;
  left: auto;
}

/* How many, and «Selecionar»: the card's last line. Once something is
   ticked it is the bar that acts on the selection, and it keeps to the top
   of the screen while the grid scrolls under it. */
.library-status {
  display: flex;
  align-items: center;
  min-height: 52px;
  margin-bottom: var(--space-4);
  padding: var(--space-2) var(--space-4);
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-top: 0;
  border-radius: 0 0 var(--r-3) var(--r-3);
}

.library-status:has(.library-bulk.is-visible) {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--ink-600);
  border-top: 1px solid var(--line-strong);
  border-color: var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

/* Under the panel's top bar below 1000px. */
@media (max-width: 999px) {
  .library-status:has(.library-bulk.is-visible) { top: 56px; }
}

.library-status__idle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem var(--space-4);
  margin: 0;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.library-status:has(.library-bulk.is-visible) .library-status__idle { display: none; }

.library-status__all {
  min-height: 32px;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text-2);
  font: inherit;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 4px;
  cursor: pointer;
}

.library-status__all:hover { color: var(--text); }

.library-bulk {
  display: none;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0;
}

.library-bulk.is-visible { display: flex; }

.library-bulk [data-selection-ids] { display: contents; }

.library-bulk__count {
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
}

.library-bulk .control {
  flex: 0 1 auto;
  width: auto;
  min-width: 12rem;
  max-width: 18rem;
}

.library-bulk__go {
  display: inline-flex;
  gap: var(--space-2);
  margin-left: auto;
}

/* --- Fotografias: the cards ------------------------------------------------- */

.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--space-4);
}

.photo-card {
  display: flex;
  flex-direction: column;
  background: var(--ink-700);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
  transition: border-color var(--fast) var(--ease);
}

.photo-card.is-selected {
  border-color: var(--red-500);
  box-shadow: 0 0 0 1px var(--red-500);
}

.photo-card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--ink-600);
}

.photo-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The whole picture is the way in. The settings live in the sheet that opens,
   not stacked underneath, which is what made this grid unusable on a phone. */
.photo-card__open {
  display: block;
  height: 100%;
}

/* The tick: always there, a ring that shows on a pale photograph as on a dark
   one, and filled red once ticked — before, ticking lit the card's edge and
   left the ring empty. The ring is 30px; what takes the press is 44px. */
.photo-card .select-toggle {
  top: 7px;
  left: 7px;
  width: 30px;
  height: 30px;
  background: rgba(20, 21, 31, 0.45);
  border: 1.5px solid rgba(255, 255, 255, 0.8);
  opacity: 1;
}

.photo-card .select-toggle::after {
  content: "";
  position: absolute;
  inset: -7px;
}

.photo-card .select-toggle:hover { background: rgba(20, 21, 31, 0.7); }

.photo-card .select-toggle:focus-within {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.photo-card.is-selected .select-toggle {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

/* On the picture only what changes what the picture is: its file archived.
   A dark pill, so the word reads on any photograph. */
.photo-card__flags {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 4px;
  max-width: calc(100% - 56px);
  pointer-events: none;
}

.photo-card__flags .badge {
  background: rgba(20, 21, 31, 0.82);
  backdrop-filter: blur(6px);
}

.photo-card__flags .badge--muted { color: var(--text-2); }

.photo-card__foot {
  display: grid;
  gap: 2px;
  align-content: start;
  min-width: 0;
  padding: var(--space-3);
}

.photo-card__name {
  margin: 0;
  overflow: hidden;
  color: var(--text);
  font-size: var(--step--1);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.photo-card__date {
  display: block;
  color: var(--text-3);
  font-size: 0.75rem;
}

/* Where it is, in words: «Galeria pública · Página inicial · the album». The
   dot hangs at the end of a line, never at the start of the next. */
.photo-card__where {
  margin: 0.3rem 0 0;
  padding: 0;
  list-style: none;
  color: var(--text-2);
  font-size: 0.75rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.photo-card__where li { display: inline; }

.photo-card__where li:not(:last-child)::after {
  content: "\00a0\00B7";
  color: var(--text-3);
}

.photo-card__review {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  gap: 0.35rem;
  min-height: 32px;
  margin-top: var(--space-2);
  padding: 0 0.6rem;
  border: 1px solid rgba(224, 177, 94, 0.45);
  border-radius: var(--r-2);
  color: var(--warn);
  font-size: 0.8125rem;
  font-weight: 600;
  transition: background var(--fast) var(--ease);
}

.photo-card__review:hover { background: var(--warn-tint); }

.library-order .order-list { margin-top: var(--space-2); }

/* The sheet's category and album side by side where they fit. */
.sheet__body .form-grid { gap: var(--space-4); }

@media (max-width: 700px) {
  /* The piles wrap, and «Mais» opens under them across the width instead of
     dropping from a corner it may not have room beside. */
  .library-bar { padding-inline: var(--space-3); }

  .library-more[open] { flex-basis: 100%; }

  .library-more__menu,
  .library-dates__fields {
    position: static;
    width: auto;
    min-width: 0;
    margin-top: var(--space-1);
    box-shadow: none;
  }

  .library-tab,
  .library-more__item { min-height: 44px; }

  /* The word and «Filtrar» first; the two lists share the next row; the
     days after. The button stays last in the form for the keyboard. */
  .library-refine__search {
    order: -2;
    flex: 1 1 calc(100% - 7rem);
  }

  .library-refine__go { order: -1; }

  .library-refine > select.control {
    flex: 1 1 40%;
    max-width: none;
  }

  .library-dates { flex: 1 1 100%; }

  .library-dates__toggle { width: 100%; }

  .library-refine .btn,
  .library-refine .control,
  .library-refine__search,
  .library-dates__toggle { min-height: 44px; }

  /* The selection bar: how many and the two buttons, then what to do. */
  .library-status { padding-inline: var(--space-3); }

  .library-bulk__count {
    order: 0;
    flex: 1 1 auto;
  }

  .library-bulk__go { order: 1; }

  .library-bulk .control {
    order: 2;
    flex: 1 1 100%;
    min-width: 0;
    max-width: none;
  }

  .library-bulk .btn { min-height: 44px; }
}

/* Two to a row on a phone: one photograph the width of the screen was a
   screen's height of scrolling per card. */
@media (max-width: 560px) {
  .photo-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
  }

  .photo-card__foot { padding: var(--space-2) var(--space-3) var(--space-3); }
}

/* --- Importar ------------------------------------------------------------------
   The files waiting, a drop box for more, and a bar at the foot of the screen
   with where they go and «Importar». What will never be imported is apart,
   below, with its own delete at the foot of its card. */

.import-pick-all {
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
}

.import-aside__count {
  color: var(--text-3);
  font-weight: 400;
}

.import-drop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: var(--space-4) var(--space-5);
  text-align: left;
}

.import-drop svg { flex-shrink: 0; }

.import-drop__text {
  display: grid;
  gap: 2px;
}

.import-none {
  margin: 0;
  color: var(--text-2);
}

.import-capped { margin: var(--space-4) 0 0; }

/* A box, its picture and its name are one thing to press. */
.incoming__file {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
  cursor: pointer;
  user-select: none;
}

.incoming__tick {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  accent-color: var(--red-500);
  cursor: pointer;
}

/* Fixed, and reserved before the picture loads: the thumbnails are fetched
   lazily one at a time, and without a size held for them every arrival would
   shift every row below it. */
.incoming__thumb {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 48px;
  overflow: hidden;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-3);
}

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

.incoming__text {
  display: grid;
  min-width: 0;
}

.incoming__name {
  min-width: 0;
  overflow-wrap: anywhere;
}

.incoming__kind {
  color: var(--text-3);
  font-size: 0.75rem;
}

/* Already in an import that has not finished: its number, under the name,
   leading to it. */
.incoming__owner {
  display: block;
  margin-top: 0.2rem;
  padding-left: calc(18px + 64px + 2 * var(--space-3));
  color: var(--warn);
  font-size: 0.75rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.incoming__folder { color: var(--text-3); }

.table--incoming .table__num { white-space: nowrap; }

/* «Como funciona» draws the line under the last row. */
.table--incoming tbody tr:last-child td { border-bottom: 0; }

.incoming__row.is-selected { background: var(--ink-600); }

/* On a phone the file is the whole first line; the folder, the size and an
   archive's button share the one under it. */
@media (max-width: 700px) {
  .table--incoming td:first-child { flex: 1 1 100%; }

  .table--incoming td:last-child,
  .table--incoming td:last-child:has(.btn) {
    order: 0;
    margin-left: auto;
  }
}

/* A press that was refused, and an archive half unpacked. */
.import-notice {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
  border-color: rgba(224, 177, 94, 0.35);
}

.import-notice p { margin: 0; }

.import-notice__bar { width: 100%; }

/* Where they go, and the press: in sight at the foot of the screen while a
   long list scrolls, and settled at the end of the form. */
.import-go {
  position: sticky;
  bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.import-go__field {
  flex: 1 1 12rem;
  min-width: 0;
  max-width: 20rem;
}

/* The album's field carries the line on who is told, so it takes more room. */
.import-go__field:has(.field__hint) {
  flex: 2 1 14rem;
  max-width: 26rem;
}

.import-go__field .field__label { margin-bottom: 0.35rem; }

.import-go__field .field__hint {
  margin-top: 0.3rem;
  font-size: 0.75rem;
}

.import-go__press {
  display: flex;
  align-items: center;
  align-self: center;
  gap: var(--space-3);
  margin-left: auto;
}

.import-go__count {
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
}

.import-go.is-visible .import-go__count {
  color: var(--text);
  font-weight: 600;
}

/* Not in the way on a phone: there the bar stays at the end of the list. */
@media (max-width: 700px) {
  .import-go {
    position: static;
    padding: var(--space-3);
  }

  .import-go__field {
    flex-basis: 100%;
    max-width: none;
  }

  .import-go__press {
    flex-basis: 100%;
    justify-content: space-between;
    margin-left: 0;
  }
}

/* Not photographs, and set aside: a name a line, the box in front of it. */
.import-aside__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.import-aside__list li { border-bottom: 1px solid var(--line); }

.import-aside__list li:last-child { border-bottom: 0; }

.import-aside__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem var(--space-3);
  min-height: 44px;
  padding: var(--space-2) var(--space-2);
  cursor: pointer;
  user-select: none;
}

.import-aside__item input {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  accent-color: var(--red-500);
}

.import-aside__name {
  flex: 1 1 12rem;
  min-width: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}

.import-aside__meta {
  color: var(--text-3);
  font-size: var(--step--1);
  white-space: nowrap;
}

/* --- One import, a step at a time -------------------------------------------------
   The bar (the space gauge's own), the file being taken, what the page has to
   say while it waits, and the buttons; below, what was left out and why. */

.import-run__now {
  margin: 0 0 var(--space-1);
  color: var(--text-2);
  overflow-wrap: anywhere;
}

.import-run__note {
  min-height: 1.5em;
  margin: 0 0 var(--space-3);
  color: var(--text-3);
  font-size: var(--step--1);
}

.import-run__note.is-warn { color: var(--warn); }

/* Held open while it runs, so a line arriving does not shift the buttons;
   once it has ended there is nothing more to say there. */
.import-run.is-ended .import-run__note:empty { display: none; }

/* While the page presses on by itself (app.js sets .is-running), «Continuar»
   has nothing to do, and the page says it has to stay open instead. */
.import-run__stay {
  display: none;
  margin: 0 0 var(--space-3);
  color: var(--text-2);
  font-size: var(--step--1);
}

.import-run.is-running .import-run__stay { display: block; }

.import-run.is-running [data-import-continue],
.import-run.is-running .import-run__space { display: none; }

.import-run__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.import-run__actions form { margin: 0; }

.import-run__end {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}

.import-run__end p { margin: 0; }

.import-run__verdict {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--step-1);
}

.import-run__verdict svg { color: var(--ok); }

.import-run__faces { margin: 0; }

/* The name first and whole on each line, the reason after it, quieter: a
   narrow window wraps the reason, never the name. */
.import-run__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
  font-size: var(--step--1);
}

.import-run__list li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.15rem var(--space-4);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
}

.import-run__name {
  min-width: 0;
  color: var(--text);
  overflow-wrap: anywhere;
}

.import-run__why { color: var(--text-3); }

.import-report__foot { margin: var(--space-3) 0 0; }

@media (max-width: 700px) {
  .import-run__actions .btn { min-height: 44px; }
}

/* --- Categorias and Vídeos: one field to add, a list whose rows open ------------ */

.media-add { margin: 0; }

.media-add__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-3);
}

.media-add__main {
  flex: 1 1 16rem;
  margin: 0;
}

/* Level with the field, under its label. */
.media-add__row > .btn {
  min-height: 52px;
  margin-top: 1.8rem;
}

.media-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.media-row { border-bottom: 1px solid var(--line); }

.media-row__summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 56px;
  padding: var(--space-2) 0;
  cursor: pointer;
  list-style: none;
}

.media-row__summary::-webkit-details-marker { display: none; }

.media-row__thumb {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 96px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-3);
}

.media-row__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media-row__main {
  display: grid;
  flex: 1 1 auto;
  gap: 2px;
  min-width: 0;
}

.media-row__title {
  color: var(--text);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.media-row__title.is-quiet {
  color: var(--text-3);
  font-weight: 500;
}

.media-row__meta {
  color: var(--text-3);
  font-size: var(--step--1);
}

.media-row__warn {
  color: var(--warn);
  white-space: nowrap;
}

.media-row__warn::before {
  content: "\00B7\00a0";
  color: var(--text-3);
}

.media-row__toggle {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  gap: 0.45rem;
  min-height: 36px;
  padding: 0 0.6rem;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 500;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.media-row__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}

.media-row__summary:hover .media-row__toggle,
.media-row__details[open] .media-row__toggle {
  background: var(--ink-600);
  color: var(--text);
}

.media-row__details[open] .media-row__toggle::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

.media-row__body { padding: var(--space-2) 0 var(--space-5); }

.media-row__body form { margin: 0; }

.media-row__body .media-row__poster { margin-bottom: var(--space-4); }

.media-row__switches {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  margin: var(--space-4) 0 0;
  padding: 0;
  border: 0;
}

.media-row__switches legend {
  float: left;
  width: 100%;
  margin-bottom: var(--space-1);
  padding: 0;
}

.media-row__order {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
}

.media-row__order .control { width: 5rem; }

.media-row__save {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--space-4);
}

.media-row .panel__foot { margin-top: var(--space-4); }

@media (max-width: 700px) {
  .media-add__row > .btn {
    flex-basis: 100%;
    margin-top: 0;
  }

  .media-row__thumb { width: 72px; }

  .media-row__toggle { min-height: 44px; }

  .media-row .btn { min-height: 44px; }
}

/* --- Imagens do site ----------------------------------------------------------
   Choosing the file sends it, so the button is the file field. */

.site-spot .panel__lead { margin: calc(var(--space-2) * -1) 0 0; }

.site-spot__form {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  margin: 0;
}

.site-spot__form .field__hint { margin: 0; }

.site-spot__pick {
  position: relative;
  cursor: pointer;
}

.site-spot__pick:focus-within {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.site-spot__pick.is-busy {
  opacity: 0.6;
  pointer-events: none;
}

.site-spot .panel__foot { margin-top: 0; }

@media (max-width: 700px) {
  .site-spot__pick { min-height: 44px; }
}

/* === Panel fix pass (2026-09-24): begin === */
/* The second pass over the photographer's panel, after QA at 900, 375 and
   1440px. Everything here is the panel's alone (.admin--studio, or the inbox's
   .admin--inbox), so the families' area does not change. */

/* --- «Avisos», folded to one line under the page head ------------------------ */

.attention-fold {
  margin: calc(var(--space-4) * -1) 0 var(--space-5);
}

.attention-fold__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  min-height: 44px;
  margin-left: -0.6rem;
  padding: 0 0.6rem;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.attention-fold__toggle::-webkit-details-marker { display: none; }

.attention-fold__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin: -3px 0 0 0.1rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}

.attention-fold[open] > .attention-fold__toggle::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

.attention-fold__toggle:hover {
  background: var(--ink-700);
  color: var(--text);
}

.attention-fold__dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-3);
}

.attention-fold--warn .attention-fold__dot { background: var(--warn); }
.attention-fold--error .attention-fold__dot { background: var(--red-400); }

.admin--studio .attention-fold .attention { margin: var(--space-2) 0 0; }

/* --- On a phone the panel reads down one left edge ------------------------------
   The site's phone rule centres display type (see «Centring on a phone»); in
   the panel it centred some titles and not the cards and lists under them. */

@media (max-width: 700px) {
  .admin--studio .admin__head,
  .admin--inbox .admin__head { justify-content: flex-start; }

  .admin--studio .admin__head h1,
  .admin--inbox .admin__head h1 { text-align: left; }

  /* And a short title keeps its button beside it, as on a wide screen. */
  .admin--studio .admin__head > div:first-child,
  .admin--inbox .admin__head > div:first-child {
    flex: 1 1 auto;
    align-items: flex-start;
  }

  .admin--studio .price-tabs { justify-content: flex-start; }

  .admin--studio .panel__head,
  .admin--inbox .panel__head { justify-content: space-between; }

  .admin--studio .admin__head .page-head__actions,
  .admin--studio .client-title { justify-content: flex-start; }

  .admin--studio .stat { text-align: left; }
}

/* --- States: a word, and a pill only for what is out of the ordinary ------------
   Eleven-pixel capitals on every row read as a wall of chips. The usual state
   (Privado, Por confirmar, Por envelope, a club) is plain quiet text; the
   coloured pills are left for what asks to be looked at. */

.admin--studio .badge {
  font-family: inherit;
  font-size: 0.75rem;
  letter-spacing: 0;
  text-transform: none;
}

.admin--studio .badge--muted {
  padding-inline: 0;
  background: none;
  color: var(--text-3);
  font-weight: 400;
}

/* On a photograph the word still needs its dark ground to be read. */
.admin--studio .photo-card__flags .badge--muted {
  padding-inline: 0.6rem;
  background: rgba(20, 21, 31, 0.82);
}

/* «Destaque» on an album tile: the pale red on its see-through tint vanished
   into a green pitch; on the same dark ground as the others, in white. */
.admin--studio .order-item__badges .badge--plate {
  background: rgba(20, 21, 31, 0.82);
  color: #fff;
}

/* A card head's text link: the words where they were, a thumb's worth of
   room to press around them. */
.admin--studio .panel__head .panel__link {
  min-height: 44px;
  margin-block: -8px;
}

/* --- Lists: the name is the way in, and the columns fit the card ---------------- */

.client-table__email {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.6rem;
  margin-top: 0.2rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

.client-table__address {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Last now that the button column is gone, and read from the left like the
   rest of the row rather than pushed to the right as a button was. */
.admin--studio .client-table td:last-child,
.admin--studio .table--albums td:last-child { text-align: left; }

.client-table__seen { white-space: nowrap; }

.client-table .badges { margin-top: 0.15rem; }

@media (max-width: 700px) {
  .admin--studio .client-table td:last-child { margin-left: 0; }
}

.client-table__note { margin: 0 0 var(--space-2); }

/* Marcações and Encomendas: the sums of every group in one column. */
@media (min-width: 561px) {
  .admin--studio .req-list { grid-template-columns: minmax(0, 1fr) 7.5rem 11rem; }
}

/* --- One album ------------------------------------------------------------------ */

/* The picker of families says it goes on below the fold of its box. */
.admin--studio .picker__list {
  max-height: 18.5rem;
  background:
    linear-gradient(var(--ink-700) 40%, rgba(43, 45, 66, 0)) top / 100% 2.5rem no-repeat local,
    linear-gradient(rgba(43, 45, 66, 0), var(--ink-700) 60%) bottom / 100% 2.5rem no-repeat local,
    radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, 0.5), transparent) top / 100% 12px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, 0.5), transparent) bottom / 100% 12px no-repeat scroll;
}

/* The cover, seen. */
.album-cover__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.album-cover__thumb {
  width: 96px;
  height: 72px;
  border-radius: var(--r-2);
  background: var(--ink-900);
  object-fit: contain;
}

.album-cover__row .field__control {
  flex: 1 1 14rem;
  width: auto;
  max-width: 20rem;
}

.album-cover__auto {
  margin: 0;
  color: var(--text-2);
}

/* Pessoas: the family, its marks beside it, «Guardar» last. */
.people-family {
  flex-wrap: wrap;
  align-items: center;
}

/* A percentage width, so the longest family name in the list does not set
   how wide the column must be: beside the side bar the table ran past its card. */
.people-family .field__control {
  flex: 1 1 12rem;
  width: 100%;
  min-width: 0;
  max-width: 22rem;
}

.people-family .badges { margin: 0; }

/* --- Preços ----------------------------------------------------------------------- */

/* A session has one note now: the room it had for two goes to the type and
   the note. Sessions and prints share the columns. */
.price-rows--session .price-rows__head,
.price-rows--session .price-row,
.price-rows--print .price-rows__head,
.price-rows--print .price-row {
  grid-template-columns: minmax(9rem, 1.2fr) 7.5rem minmax(0, 1.6fr) 6rem 7rem;
}

@container price-rows (max-width: 46rem) {
  .price-rows--session .price-row,
  .price-rows--print .price-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  .price-rows--session .price-row__cell--text,
  .price-rows--print .price-row__cell--text { grid-column: 1 / -1; }
}

@container price-rows (max-width: 30rem) {
  .price-rows--session .price-row,
  .price-rows--print .price-row { grid-template-columns: minmax(0, 1fr) 7rem; }
}

/* A line shown by the script only when asked for is display: grid, which
   outranks [hidden]. */
.price-row[hidden],
.tier-row[hidden] { display: none; }

/* The line being added: marked as new, and no «Em uso» until it has a price. */
.price-row--new {
  margin-inline: calc(var(--space-3) * -1);
  padding-inline: var(--space-3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-2);
  background: rgba(20, 21, 31, 0.25);
}

.price-row--new + .price-row--new { margin-top: var(--space-2); }

.price-row--new:has(.control--money:placeholder-shown) .price-row__cell--on { visibility: hidden; }

.price-row--new select:has(option[value='']:checked) { color: var(--text-3); }

.tier-row.price-row--new {
  margin-inline: calc(var(--space-3) * -1);
  padding-inline: var(--space-3);
}

.prices-album-note {
  margin: 0 0 var(--space-5);
  color: var(--text-3);
}

/* --- The save bar: at the form's end, and in sight only once something changed ---
   Before, a card-sized bar stood over every screen of Preços whether anything
   had been touched or not. Now it is the button at the end of the form, and
   sticks to the foot of the screen, slim, only while there is something to
   save (app.js marks it .is-dirty). */

.admin--studio .save-bar {
  position: static;
  flex-wrap: nowrap;
  margin-top: var(--space-5);
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.admin--studio .save-bar.is-dirty {
  position: sticky;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.admin--studio .save-bar__dirty { min-width: 0; }

.admin--studio .save-bar .btn { flex-shrink: 0; }

.admin--studio .price-form > .save-bar { margin-bottom: var(--space-5); }

@media (max-width: 700px) {
  .admin--studio .save-bar .btn { min-height: 44px; }
}

/* --- Fotografias ------------------------------------------------------------------ */

/* Every card the same shape: the picture in a fixed 4:3 frame, whole, on the
   dark ground. A portrait photograph used to stretch its frame, and with it
   every card in its row, to twice the height of the others. */
.admin--studio .photo-grid { align-items: start; }

/* 3:2, the camera's own shape: a landscape frame fills it, a portrait one
   stands in the middle of it. */
.admin--studio .photo-card__media {
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--ink-900);
}

.admin--studio .photo-card__open {
  position: absolute;
  inset: 0;
}

.admin--studio .photo-card__media img { object-fit: contain; }

/* «Fotografias», justified: rows of one height, each card as wide as its
   picture is at that height (--ratio, from the file), so an upright
   photograph is as tall as the others — «as fotos verticais ficam cortadas»
   no more — and the picture fills its frame exactly, nothing cropped. The
   last row keeps its height instead of stretching to the edge (::after). */
.admin--studio .photo-grid--justified {
  /* Four or five landscape frames to a row at 900px: a page of 180 to choose
     from, not a page of 180 to scroll past. */
  --row-h: 128px;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.admin--studio .photo-grid--justified::after {
  content: "";
  flex: 1000 1 0;
}

.admin--studio .photo-grid--justified .photo-card {
  flex: var(--ratio, 1.5) 1 calc(var(--ratio, 1.5) * var(--row-h));
  min-width: 0;
}

.admin--studio .photo-grid--justified .photo-card__media { aspect-ratio: var(--ratio, 1.5); }

.admin--studio .photo-grid--justified .photo-card__media img { object-fit: cover; }

@media (min-width: 1300px) {
  .admin--studio .photo-grid--justified { --row-h: 150px; }
}

@media (max-width: 560px) {
  .admin--studio .photo-grid--justified {
    --row-h: 100px;
    gap: var(--space-2);
  }
}

/* The piles in one row: it wraps where there is room, and slides sideways on
   a phone with «Mais» kept at its end. The bar's parts may be narrower than
   what is in them, or the row would widen the page instead of sliding. */
.library-tabs__row { display: contents; }

.library-bar > * { min-width: 0; }

/* The narrowings stay in the bar on a wide screen; «Filtros» is for a phone. */
.library-refine__extra { display: contents; }

.library-refine__toggle {
  display: none;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  padding: 0 0.75rem;
  background: var(--ink-600);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
}

.library-refine__toggle[aria-expanded='true'] {
  border-color: var(--line-strong);
  color: var(--text);
}

.library-refine__on {
  display: inline-grid;
  place-items: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.3rem;
  border-radius: var(--r-full);
  background: var(--text-2);
  color: var(--ink-900);
  font-size: 0.6875rem;
  font-weight: 700;
}

/* The photograph being edited, large enough to know which one it is. */
.sheet__preview {
  display: block;
  width: 100%;
  max-height: 240px;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  background: var(--ink-900);
  border-radius: var(--r-2);
}

@media (min-width: 561px) {
  .sheet__preview {
    width: 360px;
    max-width: 100%;
    height: 240px;
    aspect-ratio: auto;
    margin-inline: auto;
  }
}

@media (max-width: 700px) {
  .library-tabs {
    flex-wrap: nowrap;
    gap: 0;
  }

  .library-tabs__row {
    display: flex;
    flex: 1 1 auto;
    gap: var(--space-1);
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .library-tabs__row::-webkit-scrollbar { display: none; }

  /* The last tab in sight fades, so the row says it goes on. */
  .library-tabs__row:has(> :nth-child(3)) {
    mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
  }

  .library-tabs .library-more {
    flex-shrink: 0;
    margin-left: var(--space-1);
  }

  .library-tabs .library-more[open] { flex-basis: auto; }

  .library-tabs .library-more__menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    left: auto;
    min-width: 14rem;
    box-shadow: var(--shadow-2);
  }

  .library-refine.has-toggle .library-refine__toggle { display: inline-flex; order: -2; }

  .library-refine.has-toggle .library-refine__extra:not(.is-open) { display: none; }

  /* «Filtrar» sits with what it applies; a word typed is sent with Enter. */
  .library-refine.has-toggle .library-refine__go { order: 1; }

  .library-refine.has-toggle:not(:has(.library-refine__extra.is-open)) .library-refine__go { display: none; }

  .library-refine__search { flex-basis: 8rem; }

  .library-refine__extra.is-open {
    display: flex;
    flex: 1 1 100%;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .library-refine__extra > select.control {
    flex: 1 1 40%;
    max-width: none;
    min-height: 44px;
  }

  .library-refine__extra .library-dates { flex: 1 1 100%; }

  /* The selection bar reads in its order: how many, what to do, then do it. */
  .library-bulk .control { order: 1; }

  .library-bulk__go {
    order: 2;
    flex: 1 1 100%;
    justify-content: flex-end;
  }
}

/* --- Importar ------------------------------------------------------------------ */

.incoming__meta {
  display: none;
  color: var(--text-3);
  font-size: 0.75rem;
}

@media (max-width: 700px) {
  .incoming__meta { display: block; }

  .table--incoming .incoming__folder,
  .table--incoming .incoming__size,
  .table--incoming td:last-child:not(:has(*)) { display: none; }

  .table--incoming tr { padding-block: var(--space-2); }

  .table--incoming .incoming__thumb {
    width: 52px;
    height: 40px;
  }

  .table--incoming .incoming__owner { padding-left: calc(18px + 52px + 2 * var(--space-3)); }
}

[data-import-press]:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* A stopped import: the bar grey, not the green of a finished one. */
.import-run__gauge[hidden] { display: none; }

.import-run.is-stopped .gauge__fill { background: var(--text-3); }

/* --- Álbuns, Categorias, Envelopes ------------------------------------------------ */

.album-general { margin-top: var(--space-3); }

.album-general__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
}

.media-row--movable {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 0 var(--space-2);
}

/* Level with «Editar» while the row is closed. */
.media-row--movable:not(:has(> details[open])) { align-items: center; }

.media-row__move {
  display: flex;
  align-items: center;
  gap: 2px;
  min-height: 56px;
  margin: 0;
}


/* --- The inbox at /mensagens: the panel's bar, at every width ----------------------- */

.admin--inbox { display: block; }

.admin--inbox .studio-bar {
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 56px;
  padding: 0 clamp(1rem, 3vw, 2.5rem);
  background: var(--ink-900);
  border-bottom: 1px solid var(--line);
}

.admin--inbox .studio-bar__brand {
  display: block;
  flex-shrink: 0;
}

.admin--inbox .studio-bar__brand img {
  width: auto;
  height: 28px;
}

.admin--inbox .inbox-bar__here {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
  min-height: 44px;
  padding-left: var(--space-3);
  border-left: 1px solid var(--line);
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
}

.admin--inbox .studio-bar__tools {
  display: flex;
  align-items: center;
  margin-left: auto;
}

.admin--inbox .studio-bar__tools form { margin: 0; }

.admin--inbox .studio-bar__tool {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  padding: 0 0.75rem;
  background: none;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}

.admin--inbox .studio-bar__tool:hover { background: var(--ink-600); }

.admin--inbox .admin__main {
  max-width: 64rem;
  margin-inline: auto;
}
/* === Panel fix pass (2026-09-24): end === */

/* --- A conversation that fills the screen, and its head ----------------------
   The family's conversation and the inbox's two panes reach down to the bottom
   of the screen (app.js sets their height to what is left below them), with
   who you are talking to in the box's own head. On the inbox, the list of
   conversations sits on the left and the open one on the right, as a
   messaging app on a computer lays them out; on a phone one of the two at a
   time, the head's arrow going back to the list. */

.has-chat-fit .admin__main { padding-bottom: var(--space-3); }

.chat--app { max-width: none; }

.chat__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3.5rem;
  padding: 0.5rem 0.9rem;
  border-bottom: 1px solid var(--line);
  background: var(--ink-800);
}

.chat__back {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-left: -0.5rem;
  border-radius: var(--r-full);
  color: var(--text);
}

.chat__back:hover { background: var(--ink-700); }

.chat__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--r-full);
  background: var(--ink-700);
}

.chat__who {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.25;
}

.chat__who strong {
  color: var(--text);
  font-size: 0.9375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat__who span {
  color: var(--text-3);
  font-size: 0.75rem;
  overflow-wrap: anywhere;
}

.chat__notice {
  margin: 0;
  padding: 0.5rem 0.9rem;
  border-bottom: 1px solid var(--line);
  background: var(--ink-800);
  color: var(--text-2);
  font-size: var(--step--1);
}

.inbox-split {
  display: grid;
  grid-template-columns: minmax(16rem, 22rem) minmax(0, 1fr);
  height: clamp(24rem, calc(100dvh - 8rem), 60rem);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
  background: var(--ink-900);
}

.inbox-split__list {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--line);
  background: var(--ink-800);
}

.inbox-split__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 3.5rem;
  padding: 0.5rem 0.9rem;
  border-bottom: 1px solid var(--line);
}

.inbox-split__head h1,
.inbox-split__head h2 {
  margin: 0;
  font-size: 1.125rem;
}

.inbox-split__list .inbox__news { margin: var(--space-2) var(--space-3) 0; }

.inbox-split__none {
  margin: var(--space-4);
  color: var(--text-3);
}

.inbox-split__list .inbox__list {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  overflow-y: auto;
  border: 0;
  border-radius: 0;
}


.inbox-split__pane {
  display: flex;
  min-width: 0;
  min-height: 0;
}

.inbox-split__pane .chat {
  flex: 1 1 auto;
  height: auto;
  max-width: none;
  border: 0;
  border-radius: 0;
}

.inbox-split__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin: auto;
  padding: var(--space-5);
  color: var(--text-3);
  text-align: center;
}

@media (max-width: 760px) {
  .inbox-split {
    grid-template-columns: minmax(0, 1fr);
    border-radius: var(--r-2);
  }

  .inbox-split--thread .inbox-split__list,
  .inbox-split--index .inbox-split__pane { display: none; }

  .inbox-split__list { border-right: 0; }

  .inbox-split--thread .chat__back { display: inline-flex; }
}

/* --- Toast -------------------------------------------------------------------
   A note that comes in from the corner and can be closed (app.js remembers it
   for a few days). Above the phone's tab bar, never over the page's content
   for long, and without movement for those who asked for none. */

.toast {
  position: fixed;
  right: var(--space-4);
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: min(24rem, calc(100vw - 2rem));
  padding: var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  background: var(--ink-700);
  color: var(--text);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  transition: transform 220ms ease, opacity 220ms ease;
}

.toast[hidden] { display: none; }
.toast.is-waiting,
.toast.is-out { opacity: 0; transform: translateY(1rem); }
.toast.is-in { opacity: 1; transform: none; }

.toast__text {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.5;
}

.toast__actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.toast__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}

.toast__close:hover { background: var(--ink-600); color: var(--text); }
.toast__close[hidden] { display: none; }

@media (max-width: 999px) {
  .toast {
    left: var(--space-3);
    right: var(--space-3);
    width: auto;
    bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3));
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast { transition: none; }
}

/* The list of conversations inside the inbox's left pane: rows with room to
   breathe rather than boxes stacked edge to edge. No border on a row, and none
   on one side only: a row lights up on hover, the open conversation sits on a
   darker ground with a whole border, and an unread one says so in bold with
   its count. */
.inbox-split__list .inbox__list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2);
}

.inbox-split__list .news__link {
  gap: 0.75rem;
  padding: 0.7rem 0.75rem;
  border: 1px solid transparent;
  border-radius: var(--r-3);
  background: transparent;
}

.inbox-split__list .news__link:hover {
  border-color: transparent;
  background: var(--ink-700);
}

.inbox-split__list .news__item.is-new .news__link { border-color: transparent; }
.inbox-split__list .news__item.is-new .inbox__who strong { color: var(--text); }
.inbox-split__list .news__item.is-new .inbox__last { color: var(--text-2); }

.inbox-split__list .news__item.is-active { background: none; }

.inbox-split__list .news__item.is-active .news__link {
  border-color: var(--line-strong);
  background: var(--ink-900);
  color: var(--text);
}

.inbox-split__list .inbox__who { gap: var(--space-3); }
.inbox-split__list .inbox__last { margin-top: 0.1rem; }
.inbox-split__list .news__new { font-size: 0.6875rem; }

.inbox-split__head {
  padding: 0.75rem 1rem;
}

.inbox-split__head h1,
.inbox-split__head h2 { letter-spacing: 0; }

.chat__head { padding: 0.6rem 1rem; gap: 0.85rem; }
.chat__form { padding: 0.6rem 0.75rem; }

/* --- The photographer's menu, grouped -----------------------------------------
   The side bar Hugo liked, icons and words, with the places in four quiet
   groups: a small word over each group on a wide screen, a little space
   between the groups along the bottom bar on a phone. The page you are on
   sits on a lighter ground inside a whole border, in the site's family and
   client panels alike; no rule down one side or under one edge. */

.admin__link { border: 1px solid transparent; }

.admin__link[aria-current='page'] {
  border-color: var(--line-strong);
  background: var(--ink-700);
  color: var(--text);
}

.admin__link[aria-current='page'] svg { color: var(--red-300); opacity: 1; }

.admin__link .nav-badge { margin-left: auto; }

.admin__group {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.admin__group-name {
  margin: 0;
  padding: 0 0.85rem 0.3rem;
  color: var(--text-3);
  font-size: 0.75rem;
  font-weight: 600;
}

@media (min-width: 1000px) {
  .admin--studio .admin__nav--grouped {
    gap: var(--space-4);
    padding-bottom: var(--space-3);
  }

  .admin--studio .admin__nav--grouped .admin__link { padding: 0.55rem 0.8rem; }

  /* A screen shorter than the menu (1280 × 800 already is) scrolls the side
     bar inside itself. «Ver o site» and «Sair» stay pinned at its foot, on the
     bar's own ground under a hairline, and the places slide beneath them;
     app.js brings the page you are on into sight. */
  .admin--studio .admin__side { padding-bottom: 0; }

  .admin--studio .admin__foot {
    position: sticky;
    bottom: 0;
    z-index: 1;
    padding: var(--space-3) 0 var(--space-4);
    border-top: 1px solid var(--line);
    background: var(--ink-900);
  }
}

@media (max-width: 999px) {
  .admin__nav .admin__link[aria-current='page'] {
    border-color: transparent;
    background: var(--ink-700);
    box-shadow: none;
    color: var(--text);
  }

  /* Fifteen places do not share a phone's width, so the bar slides sideways
     with a finger, the groups a little apart, and the page you are on is
     brought into view when it opens. */
  .admin--studio .admin__nav--grouped {
    display: flex;
    gap: var(--space-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding-inline: var(--space-2);
  }

  .admin--studio .admin__nav--grouped::-webkit-scrollbar { display: none; }

  .admin--studio .admin__group {
    flex-direction: row;
    flex-shrink: 0;
  }

  .admin--studio .admin__group-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .admin--studio .admin__nav--grouped .admin__link {
    position: relative;
    flex: 0 0 auto;
    min-width: 4.25rem;
    padding: 6px 6px;
    border-radius: var(--r-2);
  }

  .admin--studio .admin__nav--grouped .nav-badge {
    position: absolute;
    top: 4px;
    right: 8px;
    margin: 0;
  }

  /* An edge with more places past it fades, so the bar says it goes on: at
     375px five places fitted exactly and nothing hinted at the other nine.
     app.js sets .is-more-left / .is-more-right as the bar moves. */
  .admin--studio .admin__nav--grouped::before,
  .admin--studio .admin__nav--grouped::after {
    content: "";
    position: fixed;
    bottom: 0;
    z-index: 1;
    width: 2.5rem;
    height: calc(56px + env(safe-area-inset-bottom, 0px));
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--fast) var(--ease);
  }

  .admin--studio .admin__nav--grouped::before {
    left: 0;
    background: linear-gradient(to right, var(--ink-900) 20%, rgba(20, 21, 31, 0));
  }

  .admin--studio .admin__nav--grouped::after {
    right: 0;
    background: linear-gradient(to left, var(--ink-900) 20%, rgba(20, 21, 31, 0));
  }

  .admin--studio .admin__nav--grouped.is-more-left::before,
  .admin--studio .admin__nav--grouped.is-more-right::after { opacity: 1; }
}

/* --- Families' area: notices they manage, prints on offer ---------------------
   client/notifications.php, client/photos.php, client/orders.php and the
   «Escrever sobre…» links on client/booking.php and client/orders.php. */

/* A notice and the way to delete it in one card: the card is the item, the
   link fills it and the cross sits at its end. The list in the inbox keeps
   its own cards (.news without --manage). */
.news--manage .news__item {
  display: flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
  transition: border-color var(--fast) var(--ease);
}

.news--manage .news__item:hover { border-color: var(--line-strong); }
.news--manage .news__item.is-new { border-color: var(--red-tint-2); }

.news--manage .news__link {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
}

.news__drop {
  flex: 0 0 auto;
  padding-right: 0.6rem;
}

.news__remove {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-3);
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.news__remove:hover,
.news__remove:focus-visible {
  color: var(--text);
  border-color: var(--line-strong);
}

.news__remove:disabled { opacity: 0.5; cursor: wait; }

@media (hover: none) {
  .news__remove { width: 44px; height: 44px; }
}

/* A phone: the words get the room the card can spare. */
@media (max-width: 560px) {
  .news--manage .news__link { gap: 0.7rem; padding: 0.8rem 0.4rem 0.8rem 0.85rem; }
  .news--manage .news__drop { padding-right: 0.25rem; }
}

/* Prints, said on the page of photographs rather than only in the bar that
   appears once some are ticked: a title, how it works in one line, one button. */
.prints-offer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
  margin-bottom: var(--space-5);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--ink-700);
}

.prints-offer__text { flex: 1 1 20rem; min-width: 0; }

.prints-offer__title {
  margin: 0 0 0.25rem;
  font-size: var(--step-0);
}

.prints-offer__text p { margin: 0; }

/* «Toca nas fotografias…»: said once the button is pressed with none ticked. */
.prints-offer__text .prints-offer__choose {
  margin-top: var(--space-2);
  color: var(--text);
}

.prints-offer__choose:empty { display: none; }

/* Choosing for prints: every photograph shows its tick, as on a touch screen. */
.gallery.is-choosing .select-toggle { opacity: 1; }

@media (max-width: 560px) {
  .prints-offer { padding: var(--space-4); }

  .prints-offer > form,
  .prints-offer > .btn { flex: 1 1 100%; }

  .prints-offer > form .btn { width: 100%; }
}

/* No orders yet: how prints work, and the albums they are ordered from. */
.orders-empty p { margin: 0; max-width: 34rem; }

.orders-empty__from {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
}

.orders-empty__albums {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.orders-empty__albums li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0 var(--space-2);
}

/* «Escrever sobre…» under a request or an order: small print beside the
   status, as «Cancelar» is (.link-button's font: inherit outranked .tiny and
   drew both at body size), and at a thumb's height on a phone. */
.booking-list__side .link-button { font-size: var(--step--1); }

@media (max-width: 700px) {
  .booking-list__side a.link-button {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* === Organisations (2026-09-24) ================================================
   The kind beside the name when making or renaming one, as narrow as its
   longest word; «Pessoas de» above the people of an album: its label, the
   select and «Guardar» on one line, the line that says it gives no access
   under them. */
.club-new .club-new__kind { flex: 0 1 11rem; }

.people-roster { margin: 0 0 var(--space-1); }

.people-roster__label {
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--text-2);
}

.people-roster .field__control--sm { flex: 0 1 16rem; }

.people-roster__hint { margin: 0 0 var(--space-5); }

@media (max-width: 480px) {
  .people-roster__label { flex-basis: 100%; }
  .people-roster .field__control--sm { flex: 1 1 10rem; }
}
/* === Organisations: end === */

/* === Identificar (2026-09-24) ==================================================
   One person, one album, a photograph at a time (admin/identify.php, on
   layouts/tool.php): the photograph as large as the window allows on a near
   black ground, the person above it, the two answers under it within a
   thumb's reach. The reference picture — the photographer's own choice, his
   eyes only — sits beside the photograph on a wide screen and in its corner on
   a phone. Selected is a filled ground or a whole border, never a line on one
   side. Then the small pieces it adds to the album page and to «Pessoas e
   famílias». */

.tool-body { background: #0E0F16; }

.identify {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  height: 100vh;
  height: 100dvh;
}

.identify--done {
  grid-template-rows: auto auto 1fr;
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
}

/* --- The bar: the way out, who, which list, how far ----------------------------- */

.identify__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: max(var(--space-2), env(safe-area-inset-top, 0px)) var(--space-4) var(--space-2);
  background: var(--ink-900);
}

.identify__exit { flex: none; }

.identify__who {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.identify__avatar {
  flex: none;
  width: 40px;
  height: 40px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  object-fit: cover;
  background: var(--ink-700);
}

.identify__names {
  display: grid;
  min-width: 0;
  margin: 0;
  line-height: 1.25;
}

.identify__names strong,
.identify__names span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.identify__names strong {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.identify__names span {
  color: var(--text-3);
  font-size: var(--step--1);
}

/* «Por decidir» and «Rever as decisões»: the one shown on a light ground. */
.identify__modes {
  display: inline-flex;
  flex: none;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
}

.identify__mode {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 34px;
  padding: 0 0.85rem;
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.identify__mode:hover {
  background: rgba(255, 255, 255, 0.05);
  color: var(--text);
}

.identify__mode.is-current {
  background: var(--text);
  color: var(--ink-900);
}

.identify__mode-count {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.identify__mode.is-current .identify__mode-count { color: var(--ink-500); }

.identify__progress {
  flex: none;
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.identify__flash { padding: 0 var(--space-4); }

.identify__flash .alert { margin: var(--space-2) 0 0; }

/* --- The photograph, and the reference beside it --------------------------------- */

.identify__stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  min-height: 0;
  padding: var(--space-3) var(--space-4);
}

.identify__stage.has-ref { grid-template-columns: 9.5rem minmax(0, 1fr); }

.identify__ref {
  display: grid;
  align-self: start;
  gap: var(--space-2);
  margin: 0;
}

.identify__ref img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  object-fit: cover;
  background: var(--ink-700);
}

.identify__ref figcaption {
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.35;
}

.identify__ref figcaption span {
  display: block;
  color: var(--text-3);
}

.identify__frame {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.identify__img {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  object-fit: contain;
}

/* In «Rever as decisões»: what was said about the one shown. */
.identify__state {
  position: absolute;
  top: var(--space-2);
  left: 50%;
  z-index: 2;
  padding: 0.2rem 0.75rem;
  transform: translateX(-50%);
  background: rgba(14, 15, 22, 0.82);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
}

.identify__state[data-state="yes"] {
  border-color: var(--text);
  color: var(--text);
}

/* --- The answers ----------------------------------------------------------------- */

.identify__controls,
.identify__crop {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4) max(var(--space-3), env(safe-area-inset-bottom, 0px));
  background: var(--ink-900);
}

.identify__answers {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 13rem));
  justify-content: center;
  gap: var(--space-3);
  margin: 0;
}

.identify__answer {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  min-height: 60px;
  padding: 0 1.25rem;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.identify__answer:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: var(--text-2);
}

.identify__answer--yes {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

.identify__answer--yes:hover {
  background: var(--red-450);
  border-color: var(--red-450);
}

/* Going through the decisions again, both answers are plain, and the one
   given is filled: red for «Está», light for «Não está». */
.identify--review .identify__answer--yes {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--text);
}

.identify--review .identify__answer--yes:hover { background: rgba(255, 255, 255, 0.05); }

.identify--review .identify__answer--yes[aria-pressed="true"] {
  background: var(--red-500);
  border-color: var(--red-500);
  color: #fff;
}

.identify--review .identify__answer--no[aria-pressed="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--ink-900);
}

.identify__answer kbd {
  padding: 0.15rem 0.4rem;
  border: 1px solid currentColor;
  border-radius: var(--r-1);
  font: 600 0.75rem/1 var(--font-body);
  opacity: 0.7;
}

.identify__minor {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-1) var(--space-2);
}

.identify__minor form { margin: 0; }

.identify__keys {
  margin: 0;
  color: var(--text-3);
  font-size: 0.75rem;
  text-align: center;
}

/* A phone has no keys to press. */
@media (hover: none), (pointer: coarse) {
  .identify__keys,
  .identify__answer kbd { display: none; }
}

/* --- Drawing the square of a reference picture ------------------------------------ */

.identify__crop {
  justify-items: center;
  text-align: center;
}

.identify__crop-hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.identify__crop-hint span {
  margin-left: 0.3em;
  color: var(--text-3);
}

.identify__crop-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

/* The square: a whole white edge, the rest of the photograph dimmed. */
.identify__cropbox {
  position: absolute;
  z-index: 3;
  border: 2px solid #fff;
  border-radius: var(--r-1);
  box-shadow: 0 0 0 100vmax rgba(8, 9, 14, 0.62);
  cursor: move;
  touch-action: none;
}

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

.identify__handle {
  position: absolute;
  right: -12px;
  bottom: -12px;
  width: 24px;
  height: 24px;
  background: #fff;
  border: 2px solid var(--ink-900);
  border-radius: 50%;
  cursor: nwse-resize;
  touch-action: none;
}

/* A thumb's reach around the handle. */
.identify__handle::after {
  content: "";
  position: absolute;
  inset: -12px;
}

.identify.is-cropping .identify__state { display: none; }

/* --- What came of it --------------------------------------------------------------- */

.identify__done {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--space-4);
  padding: var(--space-7) var(--space-4);
  text-align: center;
}

.identify__done-ref {
  width: 96px;
  height: 96px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  object-fit: cover;
}

.identify__done-title {
  margin: 0;
  font-size: var(--step-3);
}

.identify__done-lead {
  margin: 0;
  color: var(--text-2);
}

.identify__done-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.identify__done-note {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* --- Phones ------------------------------------------------------------------------- */

@media (max-width: 700px) {
  .identify__bar {
    gap: var(--space-2) var(--space-3);
    padding-inline: var(--space-3);
  }

  /* The cross alone; the word stays for a screen reader. */
  .identify__exit { padding: 0 0.6rem; }

  .identify__exit span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .identify__who { flex: 1 1 0; }
  .identify__progress { order: 2; }

  .identify__modes {
    order: 3;
    flex: 1 1 100%;
  }

  .identify__mode { flex: 1 1 0; }

  .identify__flash { padding: 0 var(--space-3); }

  .identify__stage,
  .identify__stage.has-ref {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--space-2);
  }

  /* The reference on a line of its own above the photograph, small, with its
     words beside it — never over the photograph, which has to be seen whole
     to be answered (an upright one fills the frame to its corners). */
  .identify__stage.has-ref {
    grid-template-rows: auto minmax(0, 1fr);
    gap: var(--space-2);
  }

  .identify__ref {
    grid-template-columns: 48px minmax(0, 1fr);
    align-items: center;
    gap: var(--space-3);
  }

  .identify__ref img { border-radius: var(--r-2); }

  .identify__ref figcaption span {
    display: inline;
    margin-left: 0.3em;
  }

  .identify__controls,
  .identify__crop { padding: var(--space-2) var(--space-3) max(var(--space-2), env(safe-area-inset-bottom, 0px)); }

  .identify__answers {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2);
  }

  .identify__answer { min-height: 56px; }

  /* A phone's width is a phone's: no keys to press there either. */
  .identify__keys,
  .identify__answer kbd { display: none; }

  .identify__done-actions .btn { flex: 1 1 100%; }
}

/* --- The album page: the reference in the strip and in the sub-album's head ---------- */

.subalbum-chip.has-ref { padding-left: 0.3rem; }

.subalbum-chip__ref {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--ink-600);
}

.subalbum-head__ref {
  flex: none;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  object-fit: cover;
}

.subalbum-head__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* On a phone the picture stays beside the name, not on a line of its own:
   at the top, level with it, not halfway down the family's lines. */
@media (max-width: 700px) {
  .subalbum-head__ref {
    align-self: flex-start;
    width: 40px;
    height: 40px;
  }

  .subalbum-head__ref + .subalbum-head__text { flex-basis: calc(100% - 40px - var(--space-4)); }
}

.subalbum-empty__go { margin: 0 0 var(--space-4); }

.subalbums__pop-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* --- The album page: what is done with the sub-albums (migration 036) ----------- */

/* «Dividir em subálbuns», «Imprimir envelopes para subálbuns», «Libertar todos
   os subálbuns»: one row over the strip, wrapping on a narrow window. */
.subalbums__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0 0 var(--space-4);
}

.subalbums__tools form { margin: 0; }

/* The release, with how many accounts it changes beside it. */
.subalbums__release {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

.subalbums__release .tiny { color: var(--text-3); }

/* Where the sub-album stands with the families: a line per state, the badge
   first, so «Pendente» reads before the count. */
.subalbum-delivery {
  display: grid;
  gap: 2px;
}

.subalbum-delivery__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

/* The person's envelope and its code, on one line when it fits. */
.subalbum-envelope {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

.subalbum-envelope .envelope-code { margin: 0; }

/* --- «Pessoas e famílias»: the reference beside the name, and choosing it ----------- */

.person-ref-pic {
  display: inline-block;
  width: 32px;
  height: 32px;
  margin-right: var(--space-2);
  vertical-align: middle;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  object-fit: cover;
}

/* «Identificar» and «Mais» on one line; «Mais» open takes the line below. */
.people-row__actions {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-2);
}

.people-row__actions:has(> .row-more[open]) { flex-wrap: wrap; }

.people-row__actions > .row-more[open] { flex-basis: 100%; }

/* What «Mais» opens reads from the left, like every other form of the panel,
   though its column is the right-hand one. */
.people-row__actions .row-more__body { text-align: left; }

.person-ref {
  display: grid;
  gap: var(--space-3);
}

.person-ref__title {
  margin: 0;
  color: var(--text);
  font-size: var(--step--1);
  font-weight: 600;
}

.person-ref__title span {
  margin-left: 0.4em;
  color: var(--text-3);
  font-weight: 400;
}

.person-ref__now {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.person-ref__now form { margin: 0; }

.person-ref__current {
  width: 72px;
  height: 72px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  object-fit: cover;
}

.person-ref__pick {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  margin: 0;
}

.person-ref__pick fieldset {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.person-ref__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 6px;
  width: min(22rem, 100%);
}

.person-ref__option {
  display: block;
  aspect-ratio: 1;
  overflow: hidden;
  border: 2px solid transparent;
  border-radius: var(--r-2);
  cursor: pointer;
}

.person-ref__option img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.person-ref__option:has(input:checked) { border-color: var(--text); }

.person-ref__option:has(input:focus-visible) {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
/* === Identificar: end === */

/* === Famílias (migration 032) === */

/* A person's family: the select and «Guardar», then the accounts it goes to. */
.family-accounts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-2);
  margin-top: var(--space-1);
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.4;
}

.family-accounts__label,
.family-accounts__none { color: var(--text-3); }

.family-accounts__who { color: var(--text); }

/* On the sub-album: «Família», the select and «Guardar» on one line. */
.subalbum-family {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-1) 0 0;
}

.subalbum-family__label { color: var(--text-3); }

.subalbum-family .field__control {
  flex: 0 1 16rem;
  width: auto;
  min-width: 0;
}

/* «Partilhar os subálbuns»: the button, then two lists that are never mixed. */
.share-go { margin: 0 0 var(--space-2); }

.share-list__title {
  margin: var(--space-6) 0 var(--space-1);
  font-size: var(--step-0);
}

.share-list__lead { margin: 0 0 var(--space-3); }

.share-list__none {
  margin: 0;
  color: var(--text-2);
}

.share-list__foot { margin: var(--space-4) 0 0; }

.share-plan {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.share-plan__family {
  padding: var(--space-3) var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.share-plan__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-3);
}

.share-plan__name {
  color: var(--text);
  font-weight: 600;
}

.share-plan__people {
  color: var(--text-2);
  font-size: var(--step--1);
}

.share-plan__empty {
  margin: var(--space-2) 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.share-plan__accounts {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

.share-plan__account {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-3);
}

.share-plan__who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-2);
  min-width: 0;
}

.share-plan__account-name {
  color: var(--text);
  text-decoration: none;
}

.share-plan__account-name:hover { text-decoration: underline; }

.share-plan__email {
  color: var(--text-3);
  font-size: var(--step--1);
  overflow-wrap: anywhere;
}

.share-plan__state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.share-plan__state form { margin: 0; }

/* «Já veem este álbum»: the same lines, in one box. */
.share-others .share-plan__accounts { margin-top: 0; }

.share-others__sees {
  color: var(--text-2);
  font-size: var(--step--1);
}

.share-others__manage { font-size: var(--step--1); }

/* «Famílias» and a family's page. */
.family-new {
  display: grid;
  gap: var(--space-4);
  max-width: 44rem;
}

.family-new .field { margin: 0; }

.family-new__accounts {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.family-new__accounts .field__hint { margin: 0 0 var(--space-2); }

.family-new__actions,
.family-add__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.family-add {
  display: grid;
  gap: var(--space-3);
  max-width: 44rem;
  margin-top: var(--space-5);
}

.family-add__title {
  margin: 0;
  font-size: var(--step-0);
}

.family-picker .picker__filter { width: 100%; }

/* The list of families reads left to right, people included. */
.family-table td:last-child { text-align: left; }

.family-accounts__warn {
  margin: 0 0 var(--space-3);
  color: var(--text-2);
}

.family-people {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.family-people__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-3);
}

.family-people__name { color: var(--text); }

.family-people__albums {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-2);
}

.family-people__sep { color: var(--text-3); }

/* An account's page: its families, and joining one or making one with it. */
.client-families__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.client-families__join { margin: 0; }

.client-families__join .field__control {
  flex: 0 1 18rem;
  width: auto;
  min-width: 0;
}

@media (max-width: 560px) {
  .share-plan__family { padding: var(--space-3); }

  /* The outcome under the name, not squeezed beside it. */
  .share-plan__account {
    flex-direction: column;
    align-items: flex-start;
  }

  .subalbum-family .field__control { flex: 1 1 10rem; }
}
/* === Famílias: end === */

/* === Dividir em subálbuns (migration 036) ======================================
   The wizard that replaced the automatic faces (admin/split.php, on
   layouts/tool.php): a bar of its own with the three steps, then «Pessoas» and
   «Subálbuns» as pages that scroll, and «Identificar» filling the window — the
   photograph as large as it can be, the people beside it as circles. Selected
   is a whole ring and a filled dot with a tick, or a light ground: never a
   line on one side, no gradient, no icon in a tinted square. Everything that
   is pressed is at least 44px. Hugo reviews at about 900px wide, where the
   panel keeps its column; at 760px and below it goes under the photograph. */

.split { min-height: 100vh; min-height: 100dvh; }

.split .btn--sm { min-height: 44px; }

/* --- The bar: the way out, the album, the three steps ----------------------------- */

.split-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: max(var(--space-2), env(safe-area-inset-top, 0px)) var(--space-4) var(--space-2);
  background: var(--ink-900);
  border-bottom: 1px solid var(--line);
}

.split-bar__exit { flex: none; }

.split-bar__title {
  display: grid;
  flex: 1 1 12rem;
  min-width: 0;
  margin: 0;
  line-height: 1.25;
}

.split-bar__title strong,
.split-bar__title span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.split-bar__title strong {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.split-bar__title span {
  color: var(--text-3);
  font-size: var(--step--1);
}

.split-steps ol {
  display: flex;
  gap: 2px;
  margin: 0;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  list-style: none;
}

.split-step {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0 1rem 0 0.45rem;
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.split-step:hover {
  background: rgba(255, 255, 255, 0.05);
  color: var(--text);
}

.split-step__n {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  font-variant-numeric: tabular-nums;
}

/* The step shown: the whole pill on a light ground. */
.split-step.is-current {
  background: var(--text);
  color: var(--ink-900);
}

.split-step.is-current .split-step__n { border-color: var(--ink-900); }

.split-step.is-behind .split-step__n {
  background: var(--ink-600);
  border-color: var(--ink-600);
  color: var(--text);
}

/* --- Pages that scroll: «Pessoas» and «Subálbuns» ------------------------------------ */

.split-page {
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: var(--space-5) var(--space-4) var(--space-8);
}

.split-page--narrow { max-width: 720px; }

.split-page__flash .alert { margin: 0 0 var(--space-4); }

.split-intro__title {
  margin: 0 0 var(--space-2);
  font-size: var(--step-3);
}

.split-intro__lead {
  max-width: 68ch;
  margin: 0;
  color: var(--text-2);
}

.split-note {
  max-width: 68ch;
  margin: var(--space-3) 0 0;
  padding: 0.75rem 1rem;
  background: var(--ink-800);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.split-note .link-underline { margin-left: 0.3em; }

/* Something to put right before going on (042: ids repeated in the list). */
.split-note--warn {
  border-color: var(--warn, #E0A23B);
  color: var(--text);
}

.split-empty {
  margin: var(--space-5) 0;
  color: var(--text-2);
}

.split .field__control {
  min-height: 44px;
  padding: 0.5rem 0.75rem;
}

/* The circle: the reference picture, or the id on a plain ground. */
.split-avatar {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 68px;
  height: 68px;
  overflow: hidden;
  background: var(--ink-600);
  border-radius: 50%;
}

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

.split-avatar__label {
  max-width: 88%;
  overflow: hidden;
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.split-avatar--lg { width: 96px; height: 96px; }
.split-avatar--lg .split-avatar__label { font-size: 1.5rem; }
.split-avatar--sm { width: 72px; height: 72px; }
.split-avatar--sm .split-avatar__label { font-size: 1.125rem; }
.split-avatar--xs { width: 40px; height: 40px; }
.split-avatar--xs .split-avatar__label { font-size: 0.75rem; }

/* --- Step 1: the people ---------------------------------------------------------------- */

.split-people {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-3);
  margin: var(--space-5) 0 0;
  padding: 0;
  list-style: none;
}

.split-person {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  text-align: center;
  scroll-margin-top: var(--space-5);
}

/* The one just added or just given a picture: its whole edge lit. */
.split-person:target { border-color: var(--text-2); }

.split-person__pic {
  display: block;
  border-radius: 50%;
}

.split-person__pic:hover .split-avatar { box-shadow: 0 0 0 2px var(--text-3); }

.split-person__names {
  display: grid;
  gap: var(--space-2);
  width: 100%;
  margin: var(--space-1) 0 0;
}

.split-person__field { display: block; }

.split-person__field .field__control { text-align: center; }

.split-person__label {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.split-person__save { justify-self: center; }

/* With script the fields save as they are left, and the button goes. */
.split-person__names.is-auto .split-person__save { display: none; }

.split-person__said {
  min-height: 1.2em;
  margin: 0;
  color: var(--text-3);
  font-size: 0.75rem;
}

.split-person__said.is-error { color: var(--red-300); }

.split-person__meta,
.split-sub__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--space-2);
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.split-person__meta { justify-content: center; }

.split-person__meta span + span::before,
.split-sub__meta span + span::before {
  content: "·";
  margin-right: var(--space-2);
}

.split-person__actions,
.split-sub__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.split-person__actions { justify-content: center; }

.split-person__actions form,
.split-sub__actions form { margin: 0; }

/* «Adicionar pessoa»: a way to make one, not one of them. */
.split-person--add {
  align-content: center;
  background: transparent;
  border-style: dashed;
  border-color: var(--line-strong);
}

.split-add {
  display: grid;
  gap: var(--space-3);
  width: 100%;
  margin: 0;
}

.split-add__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5.5rem;
  gap: var(--space-2);
  text-align: left;
}

.split-add__field .field__label { margin-bottom: 0.3rem; }

.split-add .tiny { margin: 0; }

.split-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-6) 0 0;
}

.split-cta form { margin: 0; }

.split-cta .btn--primary {
  min-height: 52px;
  padding: 0 1.75rem;
  font-size: 1rem;
}

.split-cta .tiny { margin: 0; }

.split-cta--end {
  justify-content: space-between;
  margin-top: var(--space-7);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

/* «Pessoas de outros álbuns». */
.split-known {
  margin-top: var(--space-7);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

.split-known__title {
  margin: 0 0 var(--space-1);
  font-size: var(--step-1);
}

.split-known__lead {
  margin: 0 0 var(--space-4);
  color: var(--text-2);
}

.split-known__search {
  display: flex;
  gap: var(--space-2);
  max-width: 32rem;
  margin: 0 0 var(--space-4);
}

.split-known__search .field__control {
  flex: 1 1 auto;
  min-width: 0;
}

.split-known__none {
  margin: 0;
  color: var(--text-3);
}

/* Not the search: its own margin is the room between it and the people
   (a plain `form` rule outranked it and the list sat on the bar). */
.split-known form:not(.split-known__search) { margin: 0; }

.split-known__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.split-known__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 56px;
  padding: 0.5rem 0.75rem;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.split-known__item:hover {
  background: rgba(255, 255, 255, 0.03);
  border-color: var(--text-3);
}

.split-known__text {
  display: grid;
  flex: 1 1 auto;
  min-width: 0;
}

.split-known__text strong,
.split-known__text span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.split-known__text strong { font-weight: 600; }

.split-known__text span {
  color: var(--text-3);
  font-size: var(--step--1);
}

.split-known__add {
  flex: none;
  color: var(--red-300);
  font-size: var(--step--1);
  font-weight: 600;
}

/* --- Step 1: choosing the picture, and cutting its square ---------------------------------- */

.split-pick__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
}

.split-pick__group {
  margin: var(--space-5) 0 var(--space-2);
  color: var(--text-2);
  font-size: var(--step-0);
  font-weight: 600;
}

.split-pick form { margin: 0; }

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

.split-pick__photo {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  overflow: hidden;
  background: var(--ink-700);
  border: 2px solid transparent;
  border-radius: var(--r-2);
  cursor: pointer;
}

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

.split-pick__photo:hover { border-color: var(--text-3); }

/* Over the whole window: the photograph on the left, the circle it makes and
   the buttons on the right. The square itself is Identificar's own
   (.identify__cropbox), drawn by the same code (app.js, squareCrop()). */
.split-crop {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  background: #0E0F16;
}

.split-crop__frame {
  position: relative;
  min-width: 0;
  min-height: 0;
  margin: var(--space-4);
  overflow: hidden;
}

.split-crop__img {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  object-fit: contain;
}

.split-crop__side {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-4) max(var(--space-4), env(safe-area-inset-bottom, 0px));
  overflow: auto;
  background: var(--ink-900);
  border-left: 1px solid var(--line);
}

.split-crop__title {
  margin: 0;
  font-size: var(--step-1);
}

.split-crop__hint {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.split-crop__hint span {
  display: block;
  margin-top: 0.2em;
  color: var(--text-3);
}

.split-crop__preview {
  align-self: center;
  width: 120px;
  height: 120px;
  background-color: var(--ink-700);
  background-repeat: no-repeat;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
}

.split-crop__preview-word {
  margin: 0;
  color: var(--text-3);
  font-size: 0.75rem;
  text-align: center;
}

.split-crop__actions {
  display: grid;
  gap: var(--space-2);
}

.split-crop .alert { margin: 0; }

/* --- Step 2: the photograph, and the people beside it --------------------------------------- */

.split--identify {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
}

.split-id {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  min-height: 0;
}

.split-id__stage {
  position: relative;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
  padding: var(--space-3);
}

.split-id__flash .alert { margin: 0 0 var(--space-2); }

.split-id__frame {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.split-id__img {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  object-fit: contain;
}

.split-id__loading {
  position: absolute;
  bottom: var(--space-5);
  left: 50%;
  margin: 0;
  padding: 0.3rem 0.85rem;
  transform: translateX(-50%);
  background: rgba(14, 15, 22, 0.85);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: var(--step--1);
}

/* Over the photograph that did not come, where the eye already is: what
   happened, «Tentar outra vez», and passing it unseen, on purpose only. */
.split-id__failed {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  gap: var(--space-3);
  width: min(22rem, calc(100% - 2 * var(--space-3)));
  padding: var(--space-4);
  transform: translate(-50%, -50%);
  background: rgba(14, 15, 22, 0.92);
  border: 1px solid var(--red-tint-2);
  border-radius: var(--r-2);
  text-align: center;
}

.split-id__failed-text {
  margin: 0;
  color: var(--red-300);
  font-size: var(--step--1);
}

.split-id__failed-actions,
.split-id__retry-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.split-id__failed-actions { justify-content: center; }

.split-id__failed-actions .btn,
.split-id__retry-actions .btn { min-height: 44px; }

.split-id__panel {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto auto auto auto;
  gap: var(--space-3);
  min-width: 0;
  min-height: 0;
  margin: 0;
  padding: var(--space-4) var(--space-4) max(var(--space-4), env(safe-area-inset-bottom, 0px));
  background: var(--ink-900);
  border-left: 1px solid var(--line);
}

.split-id__progress {
  display: grid;
  gap: 0.4rem;
}

.split-id__at {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.split-id__bar {
  height: 4px;
  overflow: hidden;
  background: var(--ink-600);
  border-radius: var(--r-full);
}

.split-id__fill {
  display: block;
  height: 100%;
  background: var(--text);
  border-radius: var(--r-full);
  transition: width var(--base) var(--ease);
}

.split-id__left {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

.split-id__people {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
}

.split-id__legend {
  margin: 0 0 var(--space-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

/* The circles scroll inside the panel; the progress above and «Continuar»
   below stay where they are. */
.split-faces {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-content: start;
  gap: var(--space-2) var(--space-1);
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 4px 2px;
  overscroll-behavior: contain;
}

.split-face {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  min-width: 0;
  padding: 0.25rem 0.15rem 0.35rem;
  border-radius: var(--r-3);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Still focusable and read as a checkbox; the circle is what is seen. */
.split-face__input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  opacity: 0;
}

.split-face__ring {
  position: relative;
  display: block;
  padding: 2px;
  border: 2px solid transparent;
  border-radius: 50%;
  transition: border-color var(--fast) var(--ease);
}

.split-face__ring .split-avatar { display: grid; }

.split-face:hover .split-face__ring { border-color: var(--text-3); }

/* Ticked: the whole ring, and a filled dot with the tick on the circle. */
.split-face.is-on .split-face__ring,
.split-face:has(.split-face__input:checked) .split-face__ring { border-color: var(--red-400); }

.split-face__check {
  position: absolute;
  right: -3px;
  bottom: -3px;
  display: none;
  place-items: center;
  width: 26px;
  height: 26px;
  background: var(--red-500);
  border: 2px solid var(--ink-900);
  border-radius: 50%;
  color: #fff;
}

.split-face__check svg { stroke-width: 3; }

.split-face.is-on .split-face__check,
.split-face:has(.split-face__input:checked) .split-face__check { display: grid; }

.split-face:has(.split-face__input:focus-visible) .split-face__ring {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.split-face__label {
  max-width: 100%;
  overflow: hidden;
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.split-face.is-on .split-face__label,
.split-face:has(.split-face__input:checked) .split-face__label { color: var(--text); }

.split-face__key {
  position: absolute;
  top: 0;
  left: 4px;
  min-width: 1.3rem;
  padding: 0.1rem 0.3rem;
  background: var(--ink-900);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-1);
  color: var(--text-3);
  font: 600 0.6875rem/1.2 var(--font-body);
  text-align: center;
}

.split-id__none {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* «Continuar» the whole width of the panel, «Anterior» under it. */
.split-id__actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
}

.split-id__actions .btn { width: 100%; }

.split-id__prev[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}

.split-id__go {
  min-height: 56px;
  font-size: 1.0625rem;
}

.split-id__kbd {
  padding: 0.15rem 0.35rem;
  border: 1px solid currentColor;
  border-radius: var(--r-1);
  font: 600 0.6875rem/1 var(--font-body);
  opacity: 0.75;
}

.split-id__said {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.split-id__said:empty { display: none; }

.split-id__retry {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: 0.75rem;
  background: var(--red-tint);
  border: 1px solid var(--red-tint-2);
  border-radius: var(--r-2);
}

.split-id__retry-text {
  margin: 0;
  color: var(--red-300);
  font-size: var(--step--1);
}

.split-id__retry .btn { justify-self: start; }

.split-id__keys {
  margin: 0;
  color: var(--text-3);
  font-size: 0.75rem;
}

/* A phone has no keys to press. */
@media (hover: none), (pointer: coarse) {
  .split-id__keys,
  .split-id__kbd,
  .split-face__key { display: none; }
}

/* --- Step 2 when every photograph is done, and step 3 ------------------------------------------ */

.split-done {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
  padding: var(--space-8) 0;
  text-align: center;
}

.split-done__title {
  margin: 0;
  font-size: var(--step-3);
}

.split-done__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.split-sums {
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--space-4);
  margin: var(--space-3) 0 0;
  color: var(--text-2);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
}

.split-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  margin: var(--space-5) 0 var(--space-4);
}

.split-toolbar form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: 0;
}

.split-toolbar__note {
  color: var(--text-3);
  font-size: var(--step--1);
}

.split-subs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.split-sub {
  display: grid;
  align-content: start;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.split-sub__who {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.split-sub__text { min-width: 0; }

.split-sub__name {
  margin: 0;
  font-size: var(--step-1);
  overflow-wrap: anywhere;
}

.split-sub__meta { margin-top: 0.15rem; }

.split-sub__state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
}

.split-sub__detail {
  color: var(--text-2);
  font-size: var(--step--1);
}

.split-sub__envelope {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

/* --- Narrower windows ---------------------------------------------------------------------------- */

@media (max-width: 1000px) {
  .split-id { grid-template-columns: minmax(0, 1fr) 18rem; }
}

/* Under 760px the panel goes below the photograph: the circles one row that
   slides sideways, «Anterior» and «Continuar» under them within a thumb's
   reach. The crop's buttons go under its photograph the same way. */
@media (max-width: 760px) {
  .split-bar {
    gap: var(--space-2) var(--space-3);
    padding-inline: var(--space-3);
  }

  /* The cross alone; the word stays for a screen reader. */
  .split-bar__exit { padding: 0 0.7rem; }

  .split-bar__exit span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .split-steps { flex: 1 1 100%; }

  .split-steps ol { justify-content: space-between; }

  .split-steps li { flex: 1 1 0; }

  .split-step {
    justify-content: center;
    width: 100%;
    padding: 0 0.6rem 0 0.35rem;
  }

  .split-page { padding: var(--space-4) var(--space-3) var(--space-7); }

  .split-id {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
  }

  .split-id__stage { padding: var(--space-2); }

  .split-id__panel {
    grid-template-rows: none;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3) max(var(--space-2), env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--line);
    border-left: 0;
  }

  .split-id__progress {
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3);
  }

  .split-id__at { font-size: var(--step-0); }

  .split-id__legend { display: none; }

  .split-faces {
    grid-auto-columns: 72px;
    grid-auto-flow: column;
    grid-template-columns: none;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
  }

  .split-face { scroll-snap-align: start; }

  .split-face .split-avatar--md {
    width: 54px;
    height: 54px;
  }

  .split-id__none { display: none; }

  /* Side by side here, «Anterior» on the left where going back is read. */
  .split-id__actions { grid-template-columns: auto minmax(0, 1fr); }

  .split-id__prev { order: -1; }

  .split-id__go { min-height: 52px; }

  .split-crop {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
  }

  .split-crop__frame { margin: var(--space-2); }

  .split-crop__side {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr);
    align-items: center;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-3);
    border-top: 1px solid var(--line);
    border-left: 0;
  }

  .split-crop__title,
  .split-crop__preview-word { display: none; }

  /* The circle on the left, the words beside it, the buttons under both. */
  .split-crop__preview {
    grid-row: 1;
    grid-column: 1;
    width: 72px;
    height: 72px;
  }

  .split-crop__hint {
    grid-row: 1;
    grid-column: 2;
  }

  .split-crop__actions,
  .split-crop .alert { grid-column: 1 / -1; }

  .split-cta--end .btn { flex: 1 1 100%; }

  .split-cta--end form { flex: 1 1 100%; }
}

@media (max-width: 480px) {
  /* The step's word only for the one shown. */
  .split-step:not(.is-current) .split-step__word {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .split-steps li { flex: 0 0 auto; }

  .split-steps li:has(.is-current) { flex: 1 1 auto; }

  .split-step:not(.is-current) { padding: 0 0.45rem; }

  .split-people { grid-template-columns: minmax(0, 1fr); }
}
/* === Dividir em subálbuns: end === */

/* === Etiquetas e equipas (037) ==============================================
   The clubs playing in an album, as their crests (partials/team-badges), and
   what kind of shoot it was, as chips (partials/album-labels): on the public
   cards and album page, on a family's cards and album page, and down the
   admin's list of albums. */

.teams {
  --team-size: 28px;
  /* The ground the badges sit on, so an overlapped crest is cut out of the
     one beside it by a ring of that ground rather than drawn over it. */
  --team-ring: var(--team-ground, var(--ink-700));
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  min-width: 0;
  max-width: 100%;
  vertical-align: middle;
}

.teams--sm { --team-size: 20px; gap: 0.25rem; }
.teams--lg { --team-size: 44px; gap: 0.625rem; }

.team {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

/* An uploaded crest on a light round plate: crests are drawn for white shirts
   and paper, and on this indigo most would lose their dark lines. The crest is
   contained in the square inside the circle, so nothing of it is ever cut. */
.team__plate {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: var(--team-size);
  height: var(--team-size);
  border-radius: 50%;
  /* Pure white: crests are drawn for white, and an off-white plate showed
     the square of a crest saved on white around it. */
  background: #fff;
  box-shadow: 0 0 0 2px var(--team-ring);
  overflow: hidden;
}

/* The badge is drawn for the circle (ClubLogos: the crest inside the circle
   unless it was framed closer), so it fills the plate and the circle cuts
   it. */
.team__logo {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* No crest uploaded: the club's place, as a plain grey shield. Quiet on
   purpose — it holds the place, it does not stand for anyone. */
.team__plate--unknown {
  background: none;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}

.team__shield {
  fill: rgba(141, 153, 174, 0.5);
  stroke: rgba(20, 21, 31, 0.6);
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
}

.team__bordure {
  fill: none;
  stroke: rgba(237, 242, 244, 0.16);
  stroke-width: 1px;
  vector-effect: non-scaling-stroke;
}

/* More than two, overlapped: a tournament's crests read as one group. A grey
   shield is narrower than a plate and has no ring to be cut out by, so it
   keeps its own room in the row instead of being buried between two plates. */
.teams--stack { gap: 0; }
.teams--stack > * + * { margin-left: -6px; }

.teams--stack > .team--unknown + *,
.teams--stack > * + .team--unknown { margin-left: 0; }

.teams__more {
  flex: none;
  display: inline-grid;
  place-items: center;
  min-width: var(--team-size);
  height: var(--team-size);
  padding-inline: 0.3em;
  border-radius: var(--r-full);
  background: var(--ink-500);
  box-shadow: 0 0 0 2px var(--team-ring);
  color: var(--text);
  font-family: var(--font-display);
  font-size: max(0.625rem, calc(var(--team-size) * 0.36));
  font-weight: 600;
  line-height: 1;
}

.teams__vs {
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.team__name {
  min-width: 0;
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.teams--md .team__name { font-size: 0.9375rem; }
.teams--lg .team__name { font-size: var(--step-1); }
.teams--lg .teams__vs { font-size: var(--step--1); }
.teams--named { gap: var(--space-2) var(--space-4); }

.album-labels {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
  max-width: 100%;
  vertical-align: middle;
}

.album-label {
  display: inline-flex;
  align-items: center;
  min-height: 1.375rem;
  max-width: 100%;
  padding: 0.125rem 0.5rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.05em;
  line-height: 1.2;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

/* What the shoot was and what it was part of, filled: one step louder than
   the age groups, of which one album can carry several. */
.album-label--type,
.album-label--competition {
  border-color: transparent;
  background: var(--ink-500);
  color: var(--text);
}

/* Where they sit. */
.collection__tags,
.album-card__tags,
.album-list__tags,
.album-head__tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  min-width: 0;
}

/* Drawn above the title, read after it (pages/collections). */
.collection__body:has(.collection__tags) {
  display: flex;
  flex-direction: column;
}

.collection__tags {
  order: -1;
  margin-bottom: 0.625rem;
}

.album-card__tags {
  --team-ground: var(--ink-600);
  margin: 0.4rem 0 0.35rem;
}

.album-card .album-label--type,
.album-card .album-label--competition { background: var(--ink-400); }

.album-list__tags { margin-top: 0.35rem; }

/* In the photographer's panel, words as its states are written there (see
   «States: a word…»): not a second wall of small capitals down every row. */
.admin--studio .album-label {
  font-family: inherit;
  font-size: 0.75rem;
  letter-spacing: 0;
  text-transform: none;
}

.table tbody tr:hover .album-list__tags { --team-ground: var(--ink-600); }

.album-head__tags {
  --team-ground: var(--ink-800);
  gap: var(--space-3) var(--space-5);
  margin-top: var(--space-4);
}

.album-head__tags--panel { margin: var(--space-3) 0 var(--space-2); }

/* The collections' filter: what kind of shoot, and which club. A heading to
   the left of each row of chips; on a phone, each row scrolls sideways so
   the albums are not pushed below the fold by it. */
.album-filters {
  display: grid;
  gap: var(--space-3);
}

.album-filters__group {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  align-items: start;
  gap: var(--space-2) var(--space-4);
}

.album-filters__kind {
  padding-top: 0.875rem;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

.album-filters__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  min-width: 0;
}

.album-filters .filter { min-height: 44px; }

/* A club is a name, not a category: written as the club writes it, which also
   keeps «Grupo Desportivo e Recreativo de…» from running across the page. */
.filter--club {
  padding-left: 0.625rem;
  font-family: var(--font-body);
  font-size: 0.875rem;
  letter-spacing: 0;
  text-transform: none;
}

.filter--club .team__name {
  font-family: inherit;
  font-weight: 500;
}

.filter--club .team__plate { box-shadow: none; }

.filter.is-empty {
  opacity: 0.45;
  cursor: default;
}

.filter.is-empty:hover {
  color: var(--text-2);
  border-color: var(--line);
}

@media (max-width: 700px) {
  .album-filters { gap: var(--space-2); }

  .album-filters__group {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-inline: calc(clamp(1rem, 3.5vw, 2.75rem) * -1);
    padding: 2px clamp(1rem, 3.5vw, 2.75rem);
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
  }

  .album-filters__group::-webkit-scrollbar { display: none; }

  .album-filters__group--all .album-filters__kind { display: none; }

  .album-filters__kind {
    flex: none;
    padding-top: 0;
  }

  .album-filters__chips { flex-wrap: nowrap; }

  .album-filters .filter { flex: none; }

  /* A page head is centred on a phone, and so are its pill rows: the crests
     and chips under a title too, and on a family's cards, whose body is. */
  .album-head__tags,
  .album-card__tags,
  .album-head__tags .teams { justify-content: center; }

  /* A match named on a phone reads as a scoreboard: each side a crest over
     its name, «vs» between them at the crests' height. A long name wraps in
     its own half instead of pushing the other side off the line. */
  .teams--named.teams--versus {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: start;
    justify-items: center;
    gap: var(--space-3);
    width: 100%;
  }

  .teams--named.teams--versus .team {
    flex-direction: column;
    gap: var(--space-2);
    text-align: center;
  }

  .teams--named.teams--versus .teams__vs {
    margin-top: calc(var(--team-size) / 2 - 0.7em);
    line-height: 1.4;
  }

  .teams--named.teams--versus.teams--lg .team__name { font-size: 1rem; }
}
/* === Etiquetas e equipas (037): end === */

/* --- Etiquetas e equipas (037): the panel ------------------------------------------------
   The admin half: «Etiquetas e equipas» in an album's «Definições», the club's
   «Emblema», and «Etiquetas». Chips are radios and checkboxes drawn as pills:
   the input lies over its chip, unseen but focusable, so the whole 44px row is
   the target and the keyboard works as it does on any radio. Chosen is a
   darker, filled ground with a whole brighter border — never a line down one
   side. */

.album-tags {
  display: grid;
  gap: var(--space-4);
}

.album-tags__group {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Floated, as in the other groups of «Definições»: an ordinary block, not a
   gap cut into a border. */
.album-tags__legend {
  float: left;
  width: 100%;
  margin-bottom: var(--space-1);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text);
}

/* Everything after it, not only the next: a hidden input can come first, and
   a list beside a full-width float would be squeezed to nothing. */
.album-tags__legend ~ * { clear: both; }

.album-tags__rule {
  margin-left: 0.35rem;
  font-weight: 400;
  color: var(--text-3);
}

.album-tags__rule::before { content: '· '; }

.tag-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-2);
}

.tag-choice {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-width: 44px;
  min-height: 44px;
  max-width: 100%;
  cursor: pointer;
}

.tag-choice__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.tag-choice__chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 34px;
  max-width: 100%;
  padding: 0.3rem 0.85rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  background: transparent;
  color: var(--text-2);
  font-size: var(--step--1);
  line-height: 1.2;
  overflow-wrap: anywhere;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}

.tag-choice:hover .tag-choice__chip {
  border-color: var(--text-3);
  color: var(--text);
}

.tag-choice__input:checked + .tag-choice__chip {
  background: var(--ink-900);
  border-color: var(--text-2);
  color: var(--text);
  font-weight: 600;
}

.tag-choice__input:focus-visible + .tag-choice__chip {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* The teams: the chosen ones in order, each with its badge and its ×, then
   the select to add one. */
.album-teams__list {
  display: grid;
  gap: var(--space-1);
  margin: 0 0 var(--space-2);
  padding: 0;
  list-style: none;
}

.album-teams__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  min-height: 44px;
  padding: 0 0 0 var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--ink-800);
}

/* The crest and the name (partials/team-badges, named), taking the room. */
.album-teams__item > .teams {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.album-teams__remove {
  flex: none;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
}

.album-teams__add {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.album-teams__add .field__control {
  flex: 1 1 14rem;
  min-width: 0;
  max-width: 24rem;
  min-height: 44px;
}

.album-teams__add .btn { min-height: 44px; }

.album-teams .field__hint {
  display: block;
  margin-top: var(--space-2);
}

/* The club's badge on its page: as the albums show it, beside what to do. */
.club-logo__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-4) var(--space-6);
}

.club-logo__current {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.club-logo__current .tiny { margin: 0; }

.club-logo__form {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
  min-width: 0;
}

.club-logo__form .field__hint { margin: 0; }

.club-logo__form .site-spot__pick { min-height: 44px; }

.club-logo .panel__foot { margin-top: var(--space-4); }

/* «Etiquetas»: a new label at the foot of its own kind. */
.label-kind__add { margin-top: var(--space-4); }

/* Every button on these two pages a whole finger high, «Subir» and «Descer»
   square. */
.label-kind .btn,
.club-logo .btn { min-height: 44px; }

.label-kind .media-row__move .btn { min-width: 44px; }

.label-kind .panel__lead { margin-top: 0; }

@media (max-width: 480px) {
  .album-teams__add .field__control { max-width: none; }

  .club-logo__row { flex-direction: column; }
}
/* --- Etiquetas e equipas (037): the panel, end ------------------------------------------- */

/* «Recortar no círculo» on an organisation's page (migration 037): the kept
   crest on white with the square on it, and beside it the circle as the site
   shows it. */
.club-crop {
  margin-top: var(--space-4);
  padding: var(--space-2) var(--space-4) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.club-crop > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  cursor: pointer;
}

.club-crop__body {
  display: grid;
  grid-template-columns: minmax(0, 320px) auto;
  gap: var(--space-5);
  align-items: start;
  margin-top: var(--space-3);
}

.club-crop__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  background: #fff;
  border-radius: var(--r-2);
  touch-action: none;
}

.club-crop__frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}

.club-crop__side {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}

.club-crop__preview {
  position: relative;
  width: 96px;
  height: 96px;
  overflow: hidden;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--line-strong);
}

.club-crop__preview img {
  position: absolute;
  top: 0;
  left: 0;
  max-width: none;
  transform-origin: 0 0;
}

.club-crop__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
}

@media (max-width: 640px) {
  .club-crop__body { grid-template-columns: minmax(0, 1fr); }
}

/* /collections: filtering behind one button (migration 037, second pass). The
   first version was a wall of chips over every visit; most visitors never
   filter, and only the sports albums carry labels. */
.page-head__side {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3) var(--space-4);
}

.page-head__side .tiny { margin: 0; }

.album-filter { position: relative; }

.album-filter__toggle {
  list-style: none;
  cursor: pointer;
}

.album-filter__toggle::-webkit-details-marker { display: none; }

.album-filter[open] > .album-filter__toggle {
  background: var(--ink-600);
  border-color: var(--line-strong);
}

.album-filter__badge {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--r-full);
  background: var(--red-500);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
}

.album-filter__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  display: grid;
  gap: var(--space-4);
  width: min(420px, calc(100vw - 32px));
  max-height: min(70vh, 560px);
  overflow: auto;
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.album-filter__kind {
  margin: 0 0 var(--space-2);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
}

.album-filter__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.album-filter__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 36px;
  padding: 0 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  font-size: 0.875rem;
  color: var(--text-2);
  text-decoration: none;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease),
    background var(--fast) var(--ease);
}

a.album-filter__chip:hover {
  border-color: var(--line-strong);
  color: var(--text);
}

.album-filter__chip[aria-current] {
  background: var(--ink-500);
  border-color: var(--text-3);
  color: var(--text);
}

.album-filter__chip.is-empty { opacity: 0.4; }

.album-filter__count {
  font-size: 0.75rem;
  color: var(--text-3);
}

.album-filter__on {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: calc(-1 * var(--space-3)) 0 var(--space-2);
}

/* On a phone the panel is a sheet at the bottom, over the page, not a box
   hanging off a button near the edge. */
@media (max-width: 560px) {
  .album-filter { position: static; }

  .album-filter__panel {
    position: fixed;
    top: auto;
    right: var(--space-4);
    bottom: var(--space-4);
    left: var(--space-4);
    width: auto;
    max-height: 70vh;
  }
}

/* «Ver por pessoa» on an album (migration 040): the same button and panel, on
   the left above the photographs, with who is chosen beside it on the same
   line. Each person is their picture and nothing else: a circle, the number
   of photographs under it, and the ring and tick of «Dividir em subálbuns»
   when chosen — a whole ring, never one side. */
.people-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin: var(--space-5) 0 var(--space-4);
  /* Each choice comes back at #pessoas: below the site's sticky header, with
     a little air. The client area's top bar does not stay on screen. */
  scroll-margin-top: calc(var(--header-h) + var(--space-3));
}

.admin .people-filter { scroll-margin-top: var(--space-5); }

.people-filter .album-filter__panel {
  right: auto;
  left: 0;
  gap: var(--space-3);
  width: min(440px, calc(100vw - 32px));
}

.people-filter__faces {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--space-3) var(--space-2);
}

.people-face {
  display: grid;
  justify-items: center;
  gap: 0.3rem;
  padding: 2px 0;
  border-radius: var(--r-3);
  color: var(--text-3);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

.people-face__ring {
  position: relative;
  display: block;
  padding: 2px;
  border: 2px solid transparent;
  border-radius: 50%;
  transition: border-color var(--fast) var(--ease);
}

.people-face__ring img {
  display: block;
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: 50%;
  background: var(--ink-600);
}

.people-face:hover .people-face__ring { border-color: var(--text-3); }

.people-face.is-on .people-face__ring { border-color: var(--red-400); }

.people-face:focus-visible { outline: none; }

.people-face:focus-visible .people-face__ring {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.people-face__check {
  position: absolute;
  right: -4px;
  bottom: -4px;
  display: none;
  place-items: center;
  width: 22px;
  height: 22px;
  background: var(--red-500);
  border: 2px solid var(--ink-800);
  border-radius: 50%;
  color: #fff;
}

.people-face__check svg { stroke-width: 3; }

.people-face.is-on .people-face__check { display: grid; }

.people-face__count {
  font-size: 0.75rem;
  line-height: 1.2;
  white-space: nowrap;
}

.people-face.is-on .people-face__count { color: var(--text); }

.people-filter__on {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

/* Who is chosen: their circle, with the × that takes them out on it. */
.people-chosen {
  position: relative;
  display: block;
  padding: 2px;
  border: 2px solid var(--red-400);
  border-radius: 50%;
  text-decoration: none;
}

.people-chosen img {
  display: block;
  width: 36px;
  height: 36px;
  object-fit: cover;
  border-radius: 50%;
  background: var(--ink-600);
}

.people-chosen__x {
  position: absolute;
  top: -5px;
  right: -5px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  background: var(--ink-500);
  border: 2px solid var(--ink-900);
  border-radius: 50%;
  color: var(--text);
  font-size: 0.8125rem;
  line-height: 1;
  transition: background var(--fast) var(--ease);
}

.people-chosen:hover .people-chosen__x { background: var(--red-500); }

.people-chosen:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.people-filter__hint,
.people-filter__count { margin: 0; color: var(--text-3); }

@media (max-width: 560px) {
  /* Above the cookie notice (90) and the selection bar (95), which sit on the
     same bottom edge: a sheet half under them hid the faces and the hint. */
  .people-filter .album-filter__panel {
    right: var(--space-4);
    left: var(--space-4);
    width: auto;
    z-index: 96;
  }

  /* In the client area the tab bar is along the bottom: the sheet sits above it. */
  .admin .people-filter .album-filter__panel {
    bottom: calc(56px + env(safe-area-inset-bottom, 0px) + var(--space-3));
    max-height: calc(70vh - 56px);
  }
}


/* --- «Equipas» (migration 042) -----------------------------------------------------------
   Teams of faces. In «Dividir em subálbuns», step 1: the album's teams and the
   others to put in, those that fit the album ticked; «Guardar estas pessoas
   como equipa» under the people; in step 2, the row of teams over the circles
   (the chosen one a whole pill on a light ground, as the step shown); in step
   3, the people in no photograph. In the panel, the teams' list and one
   team's page, with the circles of «Identificar». Selected = a whole border or
   a darker ground, never one side. */
.split-squads {
  margin: var(--space-5) 0 var(--space-4);
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.split-squads__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  font-size: var(--step-1);
}

.split-squads__lead {
  max-width: 68ch;
  margin: 0 0 var(--space-3);
  color: var(--text-2);
}

.split-squads__offer { margin: 0; }

.split-squads__given {
  display: grid;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  padding: 0;
  list-style: none;
}

.split-squad {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.split-squad.is-given {
  background: rgba(255, 255, 255, 0.03);
  border-color: var(--line-strong);
}

.split-squad__text {
  display: grid;
  flex: 1 1 14rem;
  min-width: 0;
}

.split-squad--choice .split-squad__text { flex: 1 1 auto; }

.split-squad__text strong { font-weight: 600; }

.split-squad__text span {
  color: var(--text-3);
  font-size: var(--step--1);
}

.split-squad__state {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--text-2);
  font-size: var(--step--1);
}

.split-squad__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.split-squad__actions form { margin: 0; }

.split-squads__choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
}

.split-squad--choice {
  flex-wrap: nowrap;
  min-height: 56px;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.split-squad--choice input {
  flex: none;
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--red-500);
}

.split-squad--choice:hover { border-color: var(--text-3); }

.split-squad--choice:has(input:checked) {
  background: var(--ink-700);
  border-color: var(--text-3);
}

.split-squad__hint {
  justify-self: start;
  margin-top: 0.25rem;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-size: 0.75rem;
  white-space: nowrap;
}

.split-save { margin: var(--space-5) 0 0; }

.split-save__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  color: var(--text-2);
  list-style: none;
  cursor: pointer;
}

.split-save__toggle::-webkit-details-marker { display: none; }

.split-save__toggle:hover,
.split-save[open] > .split-save__toggle { color: var(--text); }

.split-save__form {
  display: grid;
  gap: var(--space-3);
  max-width: 44rem;
  margin: var(--space-2) 0 0;
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.split-save__form .tiny { margin: 0; }

.split-save__form .btn { justify-self: start; }

.split-absent {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.split-absent .btn { flex: none; }

.split-id__teams {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 var(--space-2);
}

/* With the row of teams the panel has three rows: the circles keep the one
   that grows, the row of teams its own height (none while hidden). */
.split-id__people { grid-template-rows: auto auto minmax(0, 1fr); }

.split-id__people > .split-faces { grid-row: 3; }

.split-id__team {
  min-height: 32px;
  padding: 0 0.7rem;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  color: var(--text-2);
  font: inherit;
  font-size: var(--step--1);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}

.split-id__team:hover {
  border-color: var(--text-3);
  color: var(--text);
}

.split-id__team.is-on {
  background: var(--text);
  border-color: var(--text);
  color: var(--ink-900);
}

.split-id__team:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.squad-form { display: grid; gap: var(--space-3); }

.squad-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-3);
}

.squad-fields .field { margin: 0; }

.squad-form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.squad-list {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  padding: 0;
  list-style: none;
}

.squad-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: 0.75rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text);
  text-decoration: none;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.squad-card:hover {
  background: rgba(255, 255, 255, 0.03);
  border-color: var(--text-3);
}

.squad-card__text {
  display: grid;
  flex: 1 1 14rem;
  gap: 0.1rem;
  min-width: 0;
}

.squad-card__name { font-weight: 600; }

.squad-card__meta,
.squad-card__count {
  color: var(--text-3);
  font-size: var(--step--1);
}

/* The first faces, overlapping like a hand of cards. */
.squad-card__faces {
  display: flex;
  align-items: center;
}

.squad-card__faces .split-avatar {
  margin-left: -10px;
  box-shadow: 0 0 0 2px var(--ink-800);
}

.squad-card__faces .split-avatar:first-child { margin-left: 0; }

.squad-card__more {
  margin-left: 0.5rem;
  color: var(--text-3);
  font-size: var(--step--1);
}

.squad-faces {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--space-3) var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.squad-face {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.25rem;
  min-width: 0;
  text-align: center;
}

.squad-face__label,
.squad-face__name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.squad-face__label {
  font-size: var(--step--1);
  font-weight: 600;
}

.squad-face__name {
  color: var(--text-3);
  font-size: 0.75rem;
}

/* «Tirar da equipa»: a whole round button on the circle's corner. */
.squad-face__out {
  position: absolute;
  top: -4px;
  right: calc(50% - 46px);
  margin: 0;
}

.squad-face__remove {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  background: var(--ink-600);
  border: 2px solid var(--ink-800);
  border-radius: 50%;
  color: var(--text);
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}

.squad-face__remove:hover { background: var(--red-500); }

.squad-face__remove:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.squad-pick {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: var(--space-2) var(--space-1);
  max-height: 34rem;
  margin: var(--space-3) 0;
  padding: 4px 2px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.squad-pick-form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.squad-albums {
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.squad-albums li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-2);
}


/* --- «Instagram» (migration 043, admin/instagram.php) ------------------------------------
   One photograph at a time on layouts/tool.php: the photograph with the frame
   he moves over it on the left, and on the right the image exactly as it will
   be saved, the formats, the buttons; the strip of the photographs under it,
   and the marks' settings folded at the end. Chosen = a whole border or a
   lighter ground, never one side. */
.insta {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

.insta-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: max(var(--space-2), env(safe-area-inset-top, 0px)) var(--space-4) var(--space-2);
  background: var(--ink-900);
  border-bottom: 1px solid var(--line);
}

.insta-bar__out {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  color: var(--text-2);
  text-decoration: none;
}

.insta-bar__out:hover { color: var(--text); }

.insta-bar__title {
  display: grid;
  min-width: 0;
  line-height: 1.25;
}

.insta-bar__title strong {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.insta-bar__title span {
  color: var(--text-3);
  font-size: var(--step--1);
}

.insta-page {
  display: grid;
  gap: var(--space-4);
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--space-4);
}

.insta-page__flash .alert { margin: 0; }

.insta-page__flash:empty { display: none; }

.insta-note {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem var(--space-3);
  margin: 0;
  padding: 0.75rem 1rem;
  background: var(--ink-800);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.insta-empty {
  display: grid;
  gap: var(--space-2);
  max-width: 44rem;
}

.insta-empty h1 { margin: 0; font-size: var(--step-3); }

.insta-empty p { margin: 0; color: var(--text-2); }

.insta-work {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20rem;
  align-items: start;
  gap: var(--space-4);
}

.insta-stage { display: grid; gap: var(--space-2); min-width: 0; }

.insta-stage__hint { margin: 0; color: var(--text-3); }

/* The photograph whole, the frame over it, the rest dimmed. */
.insta-frame {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 50vh;
  /* Room for the circle that sizes the frame when the frame meets the edge. */
  padding: 14px;
  overflow: hidden;
  background: #000;
  border-radius: var(--r-2);
  user-select: none;
}

.insta-frame__img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: calc(100vh - 12rem);
  max-height: calc(100dvh - 12rem);
}

.insta-frame__wait {
  position: absolute;
  inset: auto 0 50% 0;
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  transform: translateY(50%);
  color: var(--text-3);
  text-align: center;
}

.insta-frame__wait p { margin: 0; }

.insta-box {
  position: absolute;
  z-index: 2;
  border: 2px solid #fff;
  /* The thirds, faint: where a face usually goes. */
  background-image:
    linear-gradient(to right, transparent calc(33.33% - 0.5px), rgba(255, 255, 255, 0.28) calc(33.33% - 0.5px),
      rgba(255, 255, 255, 0.28) calc(33.33% + 0.5px), transparent calc(33.33% + 0.5px),
      transparent calc(66.66% - 0.5px), rgba(255, 255, 255, 0.28) calc(66.66% - 0.5px),
      rgba(255, 255, 255, 0.28) calc(66.66% + 0.5px), transparent calc(66.66% + 0.5px)),
    linear-gradient(to bottom, transparent calc(33.33% - 0.5px), rgba(255, 255, 255, 0.28) calc(33.33% - 0.5px),
      rgba(255, 255, 255, 0.28) calc(33.33% + 0.5px), transparent calc(33.33% + 0.5px),
      transparent calc(66.66% - 0.5px), rgba(255, 255, 255, 0.28) calc(66.66% - 0.5px),
      rgba(255, 255, 255, 0.28) calc(66.66% + 0.5px), transparent calc(66.66% + 0.5px));
  box-shadow: 0 0 0 100vmax rgba(8, 9, 14, 0.62);
  cursor: move;
  touch-action: none;
}

.insta-box:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
}

.insta-box__handle {
  position: absolute;
  right: -12px;
  bottom: -12px;
  width: 24px;
  height: 24px;
  background: #fff;
  border: 2px solid var(--ink-900);
  border-radius: 50%;
  cursor: nwse-resize;
  touch-action: none;
}

.insta-box__handle::after {
  content: "";
  position: absolute;
  inset: -12px;
}

.insta-side {
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

.insta-side__at {
  margin: 0;
  font-weight: 600;
}

.insta-formats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

.insta-format {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0 0.6rem;
  min-height: 52px;
  padding: 0.45rem 0.6rem;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  color: var(--text-2);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}

.insta-format:hover {
  border-color: var(--text-3);
  color: var(--text);
}

.insta-format[aria-pressed="true"] {
  background: var(--ink-600);
  border-color: var(--text);
  color: var(--text);
}

.insta-format:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* The format's own shape, drawn: a square, a tall, a wide, a story. */
/* The longer side held to the button: 26px high, or 44px wide for the wide one,
   so every shape keeps its true proportion. */
.insta-format__shape {
  grid-row: span 2;
  justify-self: center;
  width: min(44px, calc(26px * var(--w) / var(--h)));
  height: auto;
  aspect-ratio: var(--w) / var(--h);
  border: 1.5px solid currentColor;
  border-radius: 2px;
}

.insta-format__name {
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.2;
}

.insta-format__ratio {
  color: var(--text-3);
  font-size: 0.75rem;
}

.insta-side__all { justify-self: start; }

.insta-preview {
  display: block;
  justify-self: center;
  background: #000;
  border: 1px solid var(--line);
  border-radius: var(--r-1);
}

.insta-side__size,
.insta-side__flags,
.insta-side__status {
  margin: 0;
  color: var(--text-2);
}

.insta-side__flags:empty,
.insta-side__status:empty { display: none; }

.insta-side__actions {
  display: grid;
  gap: var(--space-2);
}

.insta-side__nav {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
}

.insta-side__mixed {
  margin: 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text);
}

.insta-strip__legend {
  margin: calc(var(--space-2) * -1) 0 0;
  color: var(--text-3);
}

.insta-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.insta-strip__item {
  position: relative;
  display: block;
  width: 72px;
  height: 72px;
  padding: 0;
  overflow: hidden;
  background: var(--ink-700);
  border: 2px solid transparent;
  border-radius: var(--r-2);
  cursor: pointer;
}

.insta-strip__item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.75;
}

.insta-strip__item:hover img,
.insta-strip__item[aria-current="true"] img { opacity: 1; }

.insta-strip__item[aria-current="true"] { border-color: var(--text); }

.insta-strip__item:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.insta-strip__n {
  position: absolute;
  top: 3px;
  left: 3px;
  min-width: 18px;
  padding: 0 4px;
  background: rgba(8, 9, 14, 0.75);
  border-radius: var(--r-1);
  color: #fff;
  font-size: 0.6875rem;
  line-height: 18px;
  text-align: center;
}

/* A photograph whose frame he moved: its number on a light ground. */
.insta-strip__item.is-touched .insta-strip__n {
  background: #fff;
  color: var(--ink-900);
}

.insta-marks {
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.insta-marks__toggle {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem var(--space-3);
  min-height: 52px;
  padding: var(--space-3) var(--space-4);
  font-weight: 600;
  list-style: none;
  cursor: pointer;
}

.insta-marks__toggle::-webkit-details-marker { display: none; }

.insta-marks__toggle .tiny {
  color: var(--text-3);
  font-weight: 400;
}

.insta-marks__form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--space-4);
  padding: 0 var(--space-4) var(--space-4);
}

/* The image beside the sliders, kept in sight while they are moved. */
.insta-marks__preview {
  position: sticky;
  top: var(--space-3);
  z-index: 1;
  display: grid;
  align-self: start;
  justify-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.insta-marks__preview canvas {
  display: block;
  max-width: 100%;
  background: #000;
  border-radius: var(--r-1);
}

.insta-marks__preview figcaption {
  color: var(--text-3);
  text-align: center;
}

.insta-marks__group {
  display: grid;
  /* One column no wider than the group: the file field, a select or a
     slider label never push the group (and the page) wider than the screen. */
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: var(--space-3);
  min-width: 0;
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
}

.insta-marks__group legend {
  padding: 0 0.35rem;
  font-weight: 600;
}

.insta-marks__group .tiny { margin: 0; color: var(--text-3); }

.insta-marks__actions {
  display: flex;
  flex-wrap: wrap;
  grid-column: 1 / -1;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.insta-marks__actions .tiny { margin: 0; color: var(--text-2); }

.insta-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  min-width: 0;
  gap: 0.35rem;
}

.insta-field__label {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  color: var(--text-2);
  font-size: var(--step--1);
}

.insta-field__label output {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* The image a mark is drawn with, and the way to send another. */
.insta-mark {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
}

.insta-mark__thumb {
  max-width: 120px;
  max-height: 80px;
  object-fit: contain;
  padding: 0.35rem;
  background: repeating-conic-gradient(var(--ink-600) 0 25%, var(--ink-700) 0 50%) 0 0 / 12px 12px;
  border-radius: var(--r-1);
}

.insta-mark__file {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  color: var(--text-2);
  font-size: var(--step--1);
}

.insta-mark__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.insta-mark .tiny { margin: 0; color: var(--text-3); }

.insta-field__range {
  width: 100%;
  accent-color: var(--red-500);
}

@media (max-width: 760px) {
  .insta-work { grid-template-columns: minmax(0, 1fr); }

  .insta-frame { min-height: 40vh; }

  .insta-frame__img {
    max-height: 60vh;
    max-height: 60dvh;
  }
}


/* --- «Entregar envelopes» (migration 038)------------------------------------------------
   For a telephone at the training ground: the ID large, the face beside it,
   one press per envelope. Handed over = a whole border and a darker ground,
   with a tick in the corner; never a line down one side. */
.deliver__bar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  margin: 0 0 var(--space-4);
  padding: var(--space-3) 0;
  background: var(--ink-800);
}

.deliver__progress {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
  white-space: nowrap;
}

.deliver__progress strong {
  color: var(--text);
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-variant-numeric: tabular-nums;
}

.deliver__meter {
  height: 6px;
  overflow: hidden;
  background: var(--ink-700);
  border-radius: var(--r-full);
}

.deliver__meter span {
  display: block;
  height: 100%;
  background: var(--ok);
  border-radius: inherit;
  transition: width var(--base, 240ms) var(--ease);
}

.deliver__search {
  position: relative;
  grid-column: 1 / -1;
  display: block;
}

.deliver__search svg {
  position: absolute;
  top: 50%;
  left: 0.8rem;
  color: var(--text-3);
  transform: translateY(-50%);
  pointer-events: none;
}

.deliver__search .field__control {
  padding-left: 2.4rem;
  font-size: 1rem;
}

.deliver__piles { grid-column: 1 / -1; }

/* Buttons here, links on the photographs page: the same look, no button ground. */
.deliver__piles .library-tab {
  background: transparent;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
}

.deliver__piles .library-tab:hover { background: var(--ink-600); }

.deliver__piles .library-tab[aria-current='true'] {
  background: var(--ink-700);
  font-weight: 600;
}

.deliver-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.deliver-card {
  position: relative;
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-1);
  padding: var(--space-4) var(--space-3);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  text-align: center;
  scroll-margin-top: 9rem;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.deliver-card[hidden] { display: none; }

.deliver-card.is-done {
  background: var(--ink-700);
  border-color: var(--ok);
}

.deliver-card__check {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  display: none;
  place-items: center;
  width: 26px;
  height: 26px;
  color: var(--ink-900);
  background: var(--ok);
  border-radius: 50%;
}

.deliver-card.is-done .deliver-card__check { display: grid; }

.deliver-card .split-avatar { margin-bottom: var(--space-1); }

.deliver-card__label {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.01em;
}

.deliver-card__name {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.deliver-card__name.is-empty {
  color: var(--text-3);
  font-weight: 400;
  font-style: italic;
}

.deliver-card__family,
.deliver-card__state {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.deliver-card.is-done .deliver-card__state { color: var(--ok); }

.deliver-card__code {
  color: var(--text-3);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
}

.deliver-card__form {
  display: grid;
  justify-items: center;
  width: 100%;
  margin: var(--space-2) 0 0;
}

.deliver-card__give {
  width: 100%;
  min-height: 44px;
}

.deliver-card__form [hidden] { display: none; }

.deliver-card__error {
  margin: var(--space-1) 0 0;
  color: var(--red-300);
  font-size: 0.75rem;
}

.deliver__empty { margin-top: var(--space-4); }

.deliver__empty span { display: none; }

.deliver__empty[data-showing='todo'] [data-empty='todo'],
.deliver__empty[data-showing='done'] [data-empty='done'],
.deliver__empty[data-showing='search'] [data-empty='search'] { display: inline; }

.deliver__without { margin-top: var(--space-5); }

@media (max-width: 560px) {
  .deliver-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .deliver-card { padding: var(--space-3) var(--space-2); }
  .deliver-card .split-avatar--lg { width: 76px; height: 76px; }
}

/* A message about an album asked for by hand (migration 038): which album, a
   small line above the text inside the bubble. */
.chat__about {
  margin: 0 0 0.25rem;
  color: var(--text-3);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.chat__msg--mine .chat__about { color: inherit; opacity: 0.75; }

/* --- Asking for an album by hand (migration 038) -----------------------------------------
   The form: what happens next, three short steps; then the fields. */
.ask-steps {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-4) 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  list-style: none;
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  color: var(--text-2);
  font-size: var(--step--1);
}

.ask-steps li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.ask-steps__n {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  color: var(--text);
  font-size: 0.75rem;
  font-weight: 600;
}

.ask-private {
  margin: var(--space-3) 0 0;
  text-align: center;
}

/* «Os teus pedidos»: each ask with its three steps. Done steps are filled,
   the one waiting is outlined; no line down one side of anything. */
.asks { margin-bottom: var(--space-6); }

.asks__list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ask-card {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.ask-card--ok { border-color: var(--ok); }

.ask-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
}

.ask-card__album { font-family: var(--font-display); font-size: var(--step-1); }

.ask-track {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}

.ask-track__step {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 0.2rem;
  text-align: center;
}

/* The line between two dots, drawn from each step to the one before it. */
.ask-track__step + .ask-track__step::before {
  content: "";
  position: absolute;
  top: 11px;
  right: 50%;
  left: -50%;
  height: 2px;
  background: var(--line-strong);
}

.ask-track__step.is-done + .ask-track__step.is-done::before { background: var(--ok); }

.ask-track__dot {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  color: var(--ink-900);
  background: var(--ink-700);
  border: 2px solid var(--line-strong);
  border-radius: 50%;
}

.ask-track__step.is-done .ask-track__dot { background: var(--ok); border-color: var(--ok); }
.ask-track__step.is-no .ask-track__dot { background: var(--text-3); border-color: var(--text-3); }
.ask-track__step.is-current .ask-track__dot { background: var(--ink-900); border-color: var(--warn); }

.ask-track__label {
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
}

.ask-track__step.is-current .ask-track__label { color: var(--warn); }

.ask-track__when {
  min-height: 1em;
  color: var(--text-3);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.ask-card__said { margin: 0; color: var(--text-2); }

.ask-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.ask-card__actions:empty { display: none; }

.ask-card__actions form { margin: 0; }

/* --- Panel «Pedidos» (migration 038) ------------------------------------------------------ */
.requests-tabs { margin-bottom: var(--space-4); }

.requests {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.request-card {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  scroll-margin-top: var(--space-5);
}

.request-card__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.request-card__album {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-2);
  font-weight: 500;
  text-decoration: none;
}

.request-card__album:hover { color: var(--text); }

.request-card__body { display: grid; gap: var(--space-2); }

.request-card__body p { margin: 0; }

.request-card__child {
  display: grid;
  gap: 0.1rem;
}

.request-card__k {
  color: var(--text-3);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.request-card__child strong {
  font-family: var(--font-display);
  font-size: var(--step-2);
  line-height: 1.15;
}

.request-card__note {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  color: var(--text-2);
  background: var(--ink-700);
  border-radius: var(--r-2);
  white-space: pre-line;
}

.request-card__tools {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.request-card__tools form { margin: 0; }

.request-decide {
  display: grid;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.request-decide__who {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.request-people {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* One person to pick: a face and an ID, the way the wizard shows them. The
   chosen one gets the whole border and a lighter ground. */
.request-person {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: 4px var(--space-3) 4px 4px;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.request-person:hover { border-color: var(--line-strong); }

.request-person input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.request-person:has(input:checked) {
  background: var(--ink-600);
  border-color: var(--text-2);
}

.request-person:has(input:focus-visible) { outline: 2px solid var(--text-2); outline-offset: 2px; }

.request-person__label { font-weight: 700; }

.request-person__name {
  color: var(--text-3);
  font-size: var(--step--1);
}

.request-person--whole {
  padding-left: var(--space-4);
  border-style: dashed;
}

.request-decide__message { margin: 0; }

.request-decide__go {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

@media (max-width: 560px) {
  .request-card { padding: var(--space-4); }
}

.request-decide__message textarea { min-height: 4.5rem; }

/* --- «Contactos pelo site» in «Mensagens» (migration 039) --------------------------------
   A contact's row says so in one quiet word after the name: no chip, no
   border, no colour of its own. */
.inbox__kind {
  flex: none;
  margin-right: auto;
  color: var(--text-3);
  font-size: 0.75rem;
  font-weight: 400;
}

.inbox__archived {
  margin: 0;
  padding: 0.75rem 1rem;
}

/* The buttons beside a conversation's name drop onto their own line, to the
   right, whenever the pane is too narrow for both (Hugo reads at ~900px). */
.chat__head { flex-wrap: wrap; }

.chat__head .chat__who { flex: 1 1 10rem; }

.chat__tools {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.4rem;
  margin-left: auto;
}

.chat__tools form { margin: 0; }

/* /resposta: the person's own conversation, one card in the page. */
.reply-thread {
  max-width: 44rem;
  margin-inline: auto;
}

.reply-thread .chat { max-width: none; }

.reply-thread__note {
  margin: var(--space-3) 0 0;
  color: var(--text-3);
  text-align: center;
}

.reply-thread__gone {
  max-width: 32rem;
  margin: 0 auto;
  text-align: center;
}

/* --- The delivery sheet (envelopes-roster.php) -------------------------------------------
   Twelve people to an A4 page inside the 10 mm margin: a head with the album
   and its reference (a loose page still says which album), then three across
   and four down, 62 × 64 mm each. Light lines between them, the face large,
   the ID under it, a box to tick with a pen. No name, no code. */
.roster-sheet {
  width: 190mm;
  margin: 0 auto var(--space-6);
  padding: 0 0 2mm;
  color: #14151f;
  background: #fff;
  box-shadow: 0 1px 4px rgba(20, 21, 31, 0.12);
}

.roster-sheet__head {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6mm;
  height: 9mm;
  overflow: hidden;
  padding: 2.5mm 4mm;
  border-bottom: 0.4mm solid #14151f;
  font-size: 9pt;
}

.roster-sheet__head p { margin: 0; white-space: nowrap; }

/* A long tournament title is cut, not wrapped: a second line would push the
   fourth row of every sheet onto a page of its own. */
.roster-sheet__album {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.roster-sheet__meta { flex: none; }
.roster-sheet__album strong { font-size: 11pt; }
.roster-sheet__album span,
.roster-sheet__meta { color: #4a4d63; }
.roster-sheet__meta strong { color: #14151f; letter-spacing: 0.04em; }

.roster-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 64mm;
}

.roster-card {
  grid-template-columns: minmax(0, 1fr);
  break-inside: avoid;
}

.roster-card {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: 1mm;
  padding: 3mm 3mm 0;
  overflow: hidden;
  text-align: center;
  border-right: 0.2mm solid #d6d7de;
  border-bottom: 0.2mm solid #d6d7de;
}

.roster-card:nth-child(3n) { border-right: 0; }

.roster-card .split-avatar {
  width: 40mm;
  height: 40mm;
  background: #eceef3;
}

.roster-card .split-avatar__label {
  color: #4a4d63;
  font-size: 20pt;
}

.roster-card p { margin: 0; }

.roster-card__label {
  max-width: 100%;
  margin-top: 1.5mm !important;
  overflow: hidden;
  font-family: var(--font-display);
  font-size: 24pt;
  font-weight: 700;
  line-height: 1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A longer ID («Guarda-redes 1») in a smaller size rather than cut. */
.roster-card__label--long { font-size: 15pt; }

/* Marked «Entregue» on the telephone already: the box comes ticked. */
.roster-card__box.is-ticked {
  position: relative;
  background: #14151f;
}

.roster-card__box.is-ticked::after {
  content: "";
  position: absolute;
  left: 1.3mm;
  top: 0.4mm;
  width: 1.2mm;
  height: 2.6mm;
  border: solid #fff;
  border-width: 0 0.5mm 0.5mm 0;
  transform: rotate(45deg);
}

.roster-card__tick,
.roster-card__done {
  display: inline-flex;
  align-items: center;
  gap: 2mm;
  margin-top: 1mm !important;
  color: #4a4d63;
  font-size: 8.5pt;
}

.roster-card__box {
  width: 4.5mm;
  height: 4.5mm;
  border: 0.3mm solid #14151f;
  border-radius: 0.6mm;
}

@media print {
  .roster-sheet {
    margin: 0;
    box-shadow: none;
    break-after: page;
  }

  .roster-sheet:last-of-type { break-after: auto; }
}

@media screen and (max-width: 760px) {
  .roster-sheet { width: auto; margin-inline: var(--space-4); }
  .roster-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .roster-card:nth-child(3n) { border-right: 0.2mm solid #d6d7de; }
  .roster-card:nth-child(2n) { border-right: 0; }
}

/* Paper pages (layouts/print.php) are light: the site's dark colour-scheme
   would otherwise paint the printed page's margins dark when the browser
   prints backgrounds. */
:root:has(body.print-body) {
  color-scheme: light;
  background: #f4f4f1;
}

@media print {
  :root:has(body.print-body) { background: #fff; }
}

/* --- «Modalidades» (migration 045) -------------------------------------------------------
   The sport an album belongs to, or its other group (048). On /collections
   the bar of groups over the list (partials/collection-groups); a chip on
   the cards under «Todos»; a select on the panel's «Novo álbum» and over its
   list. Chosen = a ring or a filled ground, never a line under it. */

/* What the album is, first: filled, as «Tipo» is. */
.album-label--sport {
  border-color: transparent;
  background: var(--ink-500);
  color: var(--text);
}

.album-card .album-label--sport { background: var(--ink-400); }

.album-label--group { border-color: transparent; background: var(--ink-500); color: var(--text); }

.album-card .album-label--group { background: var(--ink-400); }

/* The groups over /collections (048): a row of small round covers with their
   names, «Todos» first. The chosen one wears a ring round its cover and its
   name in full white; never a line under it. Wider than the page, the row
   slides sideways, at every width: more groups will come. */
.group-bar {
  margin: var(--space-2) calc(clamp(1rem, 3.5vw, 2.75rem) * -1) 0;
}

.group-bar__list {
  display: flex;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-2) clamp(1rem, 3.5vw, 2.75rem) var(--space-1);
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: clamp(1rem, 3.5vw, 2.75rem);
  scrollbar-width: none;
}

.group-bar__list::-webkit-scrollbar { display: none; }

.group-bar__entry { flex: none; scroll-snap-align: start; }

.group-bar__item {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  width: 5.5rem;
  padding: var(--space-1) 0 var(--space-2);
  color: var(--text-2);
  text-align: center;
  text-decoration: none;
  border-radius: var(--r-2);
  -webkit-tap-highlight-color: transparent;
}

.group-bar__cover {
  position: relative;
  display: block;
  width: 4rem;
  height: 4rem;
  overflow: hidden;
  background: var(--ink-700);
  border-radius: 50%;
  /* The ring's place, empty until chosen: nothing moves when it fills. */
  box-shadow: 0 0 0 3px var(--ink-900), 0 0 0 4px transparent;
  transition: box-shadow 180ms var(--ease), transform 180ms var(--ease);
}

.group-bar__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cover-x, 50%) var(--cover-y, 50%);
}

/* A group of several albums: their covers in the circle, two halves for two,
   a half and two quarters for three, four quarters for four. */
.group-bar__cover--many {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
}

.group-bar__cover--many img { min-width: 0; min-height: 0; }

.group-bar__cover--many img:first-child:nth-last-child(2),
.group-bar__cover--many img:first-child:nth-last-child(2) ~ img,
.group-bar__cover--many img:first-child:nth-last-child(3) { grid-row: span 2; }

.group-bar__name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  font-size: var(--step--1);
  line-height: 1.25;
}

.group-bar__item:hover .group-bar__cover { box-shadow: 0 0 0 3px var(--ink-900), 0 0 0 4px var(--text-3); }

.group-bar__item:hover { color: var(--text); }

.group-bar__item[aria-current="page"] { color: var(--text); font-weight: 600; }

.group-bar__item[aria-current="page"] .group-bar__cover {
  box-shadow: 0 0 0 3px var(--ink-900), 0 0 0 5px var(--text);
}

.group-bar__item:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }

.group-bar__item:active .group-bar__cover { transform: scale(0.96); }

@media (max-width: 700px) {
  .group-bar__item { width: 4.75rem; }

  .group-bar__cover { width: 3.5rem; height: 3.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .group-bar__cover { transition: none; }
}

/* «Novo álbum» with its sport: the title has the first row, and the date, the
   sport, the note and the button the second — five fields across left each of
   them too narrow beside the panel's menu; then two by two on a phone. */
.album-new__form--sport {
  grid-template-columns: minmax(9.5rem, 1fr) minmax(11rem, 1.1fr) minmax(0, 1.4fr) auto;
}

.album-new__form--sport .album-new__title { grid-column: 1 / -1; }

/* The list's search, «Modalidade» and the order: a finger high, on a row of
   their own under the list's title — three beside it squeezed the search. */
.album-list__tools--sport { flex: 1 1 100%; }

.album-list__tools--sport .toolbar__search,
.album-list__tools--sport .album-list__sort { min-height: 44px; }

.album-list__tools--sport .toolbar__search { flex-basis: 16rem; }

@media (max-width: 760px) {
  .album-new__form--sport { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  .album-new__form--sport .album-new__note { grid-column: 1 / -1; }
}

@media (max-width: 480px) {
  .album-new__form--sport { grid-template-columns: minmax(0, 1fr); }
}

/* A team's four fields with its sport: two by two, not three and one left
   over; one under the other on a phone. */
.squad-fields--sport { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 560px) {
  .squad-fields--sport { grid-template-columns: minmax(0, 1fr); }
}

/* --- «Modalidades»: end ------------------------------------------------------------------ */

/* --- «Agenda» (migration 046, agenda/*.php, partials/agenda-*.php) -----------------------
   The «Gestão» panel's second place. Its bar with two places; the board as
   Trello's lists — one wide column a day, Monday to Sunday, in a row that
   slides inside itself so the page never widens; a card per item whose level
   is told by its border and ground (solid, dashed amber, dashed quiet),
   never by a stripe down one side; the item's sheet «como no Notion»: a title
   with no box, one property a row, the notes as its body. Everything pressed
   is at least 44px. */

/* The bar: «Mensagens» and «Agenda» side by side, the one you are on on a
   lighter ground inside a whole border, as the panel's menu marks it — the
   old line down the left of the single place is gone with it. */
.admin--inbox .inbox-bar__places {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}

.admin--inbox .inbox-bar__here {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  padding: 0 0.75rem;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.admin--inbox .inbox-bar__here:hover {
  background: var(--ink-700);
  color: var(--text);
}

.admin--inbox .inbox-bar__here[aria-current='page'] {
  background: var(--ink-700);
  border-color: var(--line-strong);
  color: var(--text);
}

.admin--inbox .inbox-bar__here svg { flex-shrink: 0; opacity: 0.85; }

.admin--inbox .inbox-bar__here .nav-badge { margin-left: 0.1rem; }

/* A phone: the two places keep their words, the way out keeps its glyph. */
@media (max-width: 560px) {
  .admin--inbox .studio-bar { gap: var(--space-2); }

  .admin--inbox .inbox-bar__here {
    gap: 0.35rem;
    padding: 0 0.55rem;
    font-size: 0.875rem;
  }

  .admin--inbox .inbox-bar__here > svg { display: none; }

  .admin--inbox .studio-bar__tool {
    min-width: 44px;
    justify-content: center;
    padding: 0 0.6rem;
  }

  .admin--inbox .studio-bar__tool > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* The board takes the whole width; the conversations keep their column. */
.admin--inbox .admin__main--wide { max-width: none; }

/* --- The head and the bar over the board --------------------------------------------- */

.agenda-head { margin-bottom: var(--space-4); }

.admin--inbox .agenda-head .btn--sm,
.agenda-bar .btn--sm,
.agenda-split .btn--sm,
.agenda-month__day .btn--sm,
.agenda-form__foot .btn--sm,
.agenda-slots .btn--sm { min-height: 44px; }

.agenda-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-4);
}

.agenda-bar__views { gap: var(--space-1); }

.agenda-bar__views .library-tab { min-height: 44px; }

.agenda-bar__step {
  display: inline-flex;
  gap: var(--space-1);
}

.agenda-bar__arrow {
  min-width: 44px;
  padding: 0;
  font-size: 1.25rem;
  line-height: 1;
}

/* «Filtrar» at the bar's end, its panel a form. */
.agenda-filter { margin-left: auto; }

.agenda-filter__panel { gap: var(--space-4); }

.agenda-filter__group {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.agenda-filter__group .album-filter__kind { display: block; }

.agenda-filter__panel .field__control {
  min-height: 44px;
  padding-block: 0.5rem;
}

.agenda-filter__check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  color: var(--text-2);
  font-size: 0.9375rem;
  cursor: pointer;
}

.agenda-filter__check input {
  width: 18px;
  height: 18px;
  accent-color: var(--red-500);
}

.agenda-filter__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.agenda-filter__actions .btn { min-height: 44px; }

/* What a drag that did not save says, where the eye is: not a toast. */
.agenda-status {
  margin: 0 0 var(--space-3);
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  background: var(--ink-700);
  color: var(--text-2);
  font-size: var(--step--1);
}

.agenda-status.is-error {
  border-color: var(--red-500);
  color: var(--red-300);
}

/* --- Semana: the board ------------------------------------------------------------------ */

/* Positioned, so what is hidden inside the cards for a screen reader is
   held by the row that slides, and never widens the page past its edge. */
.agenda-board {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(16rem, 1fr);
  gap: var(--space-3);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 0;
  padding-bottom: var(--space-2);
  border-radius: var(--r-3);
}

.agenda-board:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.agenda-day {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  scroll-snap-align: start;
  overflow: hidden;
}

/* Today: a lighter ground in a whole, stronger border. */
.agenda-day.is-today {
  background: var(--ink-700);
  border-color: var(--line-strong);
}

/* Somewhere to drop a dragged card. */
.agenda-day.is-drop { border-color: var(--blue); }

.agenda-day__head {
  flex: none;
  margin: 0;
  font-size: inherit;
}

.agenda-day__date {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: 0 var(--space-3);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.agenda-day__date:hover { background: var(--ink-800); }

/* Inside the column's own rounded edge, which would cut a ring drawn outside. */
.agenda-day__date:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: -3px;
  border-radius: var(--r-3) var(--r-3) var(--r-1) var(--r-1);
}

.agenda-day.is-today .agenda-day__date:hover { background: var(--ink-600); }

.agenda-day__today {
  color: var(--red-300);
  font-size: var(--step--1);
  font-weight: 600;
}

/* The days gone: quieter, still there — a sure card's ground a step
   darker, its words as readable as any other day's. */
.agenda-day.is-past .agenda-day__date { color: var(--text-3); }

.agenda-day.is-past .agenda-card--confirmed {
  --team-ground: var(--ink-700);
  background: var(--ink-700);
  border-color: rgba(111, 195, 160, 0.5);
}

.agenda-day__list {
  flex: 1 1 auto;
  display: grid;
  align-content: start;
  gap: var(--space-2);
  min-height: 0;
  margin: 0;
  padding: 4px var(--space-2) var(--space-2);
  list-style: none;
  overflow-y: auto;
}

.agenda-day__item { min-width: 0; }

/* «+ Adicionar» at the foot of a day, as Trello's. */
.agenda-day__add {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  margin: 0 var(--space-2) var(--space-2);
  padding: 0 var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text-3);
  font-size: 0.875rem;
  font-weight: 500;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.agenda-day__add:hover {
  background: var(--ink-600);
  border-color: var(--line);
  color: var(--text);
}

/* A phone: one column and the edge of the next, snapping to each; the page
   scrolls, not the columns. */
@media (max-width: 560px) {
  .agenda-board {
    grid-auto-columns: 86vw;
    scroll-snap-type: x mandatory;
  }

  .agenda-day__list { overflow: visible; }
}

/* --- A card ----------------------------------------------------------------------------- */

.agenda-card {
  --team-ground: var(--ink-600);
  display: grid;
  gap: 0.3rem;
  min-height: 44px;
  min-width: 0;
  padding: 0.65rem 0.75rem;
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text);
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.agenda-card:hover { border-color: var(--text-3); }

.agenda-card:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* Confirmado: a whole green border, the word in green. */
.agenda-card--confirmed { border-color: var(--ok); }

.agenda-card--confirmed:hover { border-color: var(--ok); background: var(--ink-500); }

/* Não vou: it happens, he will not be there — no ground, grey, the crests
   without their colours. */
.agenda-card--declined {
  --team-ground: var(--ink-900);
  background: transparent;
  border-color: var(--line);
  color: var(--text-3);
}

.agenda-day.is-today .agenda-card--declined { --team-ground: var(--ink-700); }

.agenda-card--declined .agenda-card__time,
.agenda-card--declined .agenda-card__meta,
.agenda-card--declined .agenda-card__place,
.agenda-card--declined .agenda-card__span { color: var(--text-3); }

.agenda-card--declined .teams { filter: grayscale(1); opacity: 0.7; }

/* Incerto: dashed amber, a step darker, the word in amber. */
.agenda-card--tentative {
  --team-ground: var(--ink-700);
  background: var(--ink-700);
  border-style: dashed;
  border-color: var(--warn);
}

.agenda-card--tentative:hover { border-color: var(--warn); background: var(--ink-600); }

/* Listado: no ground, a quiet dashed line — only known of. */
.agenda-card--listed {
  --team-ground: var(--ink-900);
  background: transparent;
  border-style: dashed;
  border-color: var(--line-strong);
  color: var(--text-2);
}

.agenda-day.is-today .agenda-card--listed { --team-ground: var(--ink-700); }

/* Cancelado: only with «Mostrar cancelados», struck through. */
.agenda-card--cancelled {
  background: transparent;
  border-color: var(--line);
  color: var(--text-3);
}

.agenda-card--cancelled .agenda-card__who,
.agenda-card--cancelled .agenda-card__meta,
.agenda-card--cancelled .agenda-card__time { text-decoration: line-through; }

.agenda-card__top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--space-2);
  font-size: var(--step--1);
}

.agenda-card__time {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.agenda-card--listed .agenda-card__time { color: var(--text-2); }

.agenda-card__date {
  color: var(--text-2);
  font-weight: 500;
}

.agenda-card__status {
  color: var(--text-3);
  font-size: 0.75rem;
  font-weight: 500;
}

.agenda-card--tentative .agenda-card__status { color: var(--warn); }

.agenda-card--confirmed .agenda-card__status { color: var(--ok); }

.agenda-card__who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
}

.agenda-card__who .teams--named { gap: 0.3rem 0.5rem; }

.agenda-card__who .team__name { font-size: 0.9375rem; }

/* Beside its crest, wrapping in its own room rather than under it. */
.agenda-card__heading {
  flex: 1 1 8rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.agenda-card__who > .teams:not(.teams--named) { flex: none; }

.agenda-card__sub {
  color: var(--text-2);
  font-size: var(--step--1);
}

.agenda-card__meta {
  color: var(--text-2);
  font-size: 0.8125rem;
  line-height: 1.4;
}

.agenda-card--listed .agenda-card__meta,
.agenda-card--cancelled .agenda-card__meta { color: var(--text-3); }

.agenda-card__place {
  display: flex;
  align-items: flex-start;
  gap: 0.35rem;
  color: var(--text-2);
  font-size: 0.8125rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.agenda-card__place svg {
  flex: none;
  margin-top: 0.1rem;
}

.agenda-card__span {
  color: var(--text-2);
  font-size: 0.75rem;
}

/* On the cards with no ground of their own, the quieter grey still reads. */
.agenda-card--listed .agenda-card__place,
.agenda-card--listed .agenda-card__span,
.agenda-card--cancelled .agenda-card__place,
.agenda-card--cancelled .agenda-card__span { color: var(--text-3); }

.agenda-card.is-dragging { opacity: 0.45; }

/* --- Dia: the day's list and the item beside it ------------------------------------------- */

@media (min-width: 761px) {
  .agenda-split { grid-template-columns: minmax(15rem, 20rem) minmax(0, 1fr); }
}

.agenda-split__list {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: var(--space-2) 0;
  list-style: none;
  overflow-y: auto;
}

.agenda-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.1rem 0.6rem;
  min-height: 56px;
  margin: 2px var(--space-2);
  padding: 0.55rem 0.8rem;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text);
  transition: background var(--fast) var(--ease);
}

.agenda-row:hover { background: var(--ink-700); }

.agenda-row.is-active {
  background: var(--ink-700);
  border-color: var(--line-strong);
}

.agenda-row__time {
  font-size: var(--step--1);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.agenda-row__status {
  color: var(--text-3);
  font-size: 0.75rem;
  text-align: right;
}

.agenda-row--tentative .agenda-row__status { color: var(--warn); }

.agenda-row--listed .agenda-row__heading,
.agenda-row--listed .agenda-row__time { color: var(--text-2); }

.agenda-row--cancelled .agenda-row__heading { color: var(--text-3); text-decoration: line-through; }

.agenda-row--confirmed .agenda-row__status { color: var(--ok); }

.agenda-row--declined .agenda-row__heading,
.agenda-row--declined .agenda-row__time { color: var(--text-3); }

.agenda-row__heading {
  grid-column: 1 / -1;
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
}

.agenda-split__pane {
  flex-direction: column;
  overflow-y: auto;
}

.agenda-split__head {
  display: none;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4) 0;
}

.agenda-split__time {
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 760px) {
  .inbox-split--thread .agenda-split__head { display: flex; }
}

.agenda-split__form { padding: var(--space-4); }

/* On a phone the day is a page that scrolls, as the week is ([data-fit] only
   fits from 700px): no box the height of the screen with a second scroll in
   it, and «Guardar», once something changed, held at the foot of the window. */
@media (max-width: 699px) {
  .agenda-split {
    height: auto;
    overflow: visible;
  }

  .agenda-split__list,
  .agenda-split__pane { overflow: visible; }

  .agenda-split__form .agenda-form__save.is-dirty { bottom: env(safe-area-inset-bottom, 0px); }
}

/* The way back to the day's list, a thumb's size. */
.agenda-split__head .chat__back {
  width: 44px;
  height: 44px;
}

/* --- Mês ------------------------------------------------------------------------------- */

.agenda-month__names,
.agenda-month__grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}

.agenda-month__names {
  margin-bottom: 4px;
  color: var(--text-3);
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.agenda-month__names span { padding: 0 0.5rem; }

.agenda-month__grid {
  margin: 0;
  padding: 0;
  list-style: none;
}

.agenda-month__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  min-height: 7.5rem;
  padding: 0.3rem 0.35rem 0.4rem;
  background: var(--ink-900);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  transition: border-color var(--fast) var(--ease);
}

.agenda-month__cell:hover { border-color: var(--text-3); }

.agenda-month__cell.is-other { background: transparent; }

.agenda-month__cell.is-other .agenda-month__date { color: var(--text-3); }

.agenda-month__cell.is-today {
  background: var(--ink-700);
  border-color: var(--line-strong);
}

.agenda-month__cell.is-today .agenda-month__date { color: var(--red-300); }

/* The date, and over the whole cell its link: one target to the day. */
.agenda-month__date {
  align-self: flex-start;
  padding: 0.1rem 0.25rem;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 600;
}

.agenda-month__date::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.agenda-month__date:focus-visible { outline: none; }

.agenda-month__date:focus-visible::after {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.agenda-month__pick,
.agenda-month__day { display: none; }

.agenda-month__lines {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.agenda-month__line {
  display: flex;
  gap: 0.3rem;
  min-width: 0;
  padding: 0.1rem 0.35rem;
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-1);
  color: var(--text);
  font-size: 0.75rem;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
}

.agenda-month__line > span:last-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.agenda-month__line--confirmed { border-color: var(--ok); }

.agenda-month__line--tentative {
  background: var(--ink-700);
  border-style: dashed;
  border-color: var(--warn);
}

.agenda-month__time {
  flex: none;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.agenda-month__more,
.agenda-month__listed {
  margin: 0;
  padding: 0 0.35rem;
  color: var(--text-3);
  font-size: 0.75rem;
  line-height: 1.35;
}

/* A phone: a small grid with a count under each day, and the chosen day's
   cards under it. */
@media (max-width: 699px) {
  .agenda-month__names,
  .agenda-month__grid { gap: 2px; }

  .agenda-month__names span {
    padding: 0;
    text-align: center;
  }

  .agenda-month__cell {
    min-height: 0;
    padding: 0;
    background: none;
    border: 0;
  }

  .agenda-month__cell.is-today,
  .agenda-month__cell.is-other { background: none; }

  .agenda-month__date,
  .agenda-month__lines,
  .agenda-month__more,
  .agenda-month__listed { display: none; }

  .agenda-month__pick {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 52px;
    border: 1px solid transparent;
    border-radius: var(--r-2);
    color: var(--text);
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
  }

  .agenda-month__cell.is-other .agenda-month__pick { color: var(--text-3); }

  .agenda-month__cell.is-today .agenda-month__pick { color: var(--red-300); }

  .agenda-month__pick[aria-current='true'] {
    background: var(--ink-700);
    border-color: var(--line-strong);
  }

  .agenda-month__count {
    min-height: 0.8rem;
    color: var(--text-3);
    font-family: var(--font-body);
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1;
  }

  .agenda-month__day {
    display: block;
    margin-top: var(--space-5);
    scroll-margin-top: calc(56px + var(--space-3));
  }
}

.agenda-month__day-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.agenda-month__day-head h2 {
  margin: 0;
  font-size: var(--step-1);
}

.agenda-month__cards {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* --- The item: the sheet, the page and the pane --------------------------------------------- */

.sheet.agenda-sheet {
  width: min(46rem, calc(100vw - 2rem));
  max-height: min(56rem, 92svh);
}

.agenda-sheet[open] {
  display: flex;
  flex-direction: column;
}

@media (max-width: 560px) {
  .sheet.agenda-sheet {
    width: 100vw;
    max-height: 92svh;
  }
}

.agenda-sheet__head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-5);
  border-bottom: 1px solid var(--line);
}

.agenda-sheet__day {
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 500;
}

.agenda-sheet__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--space-4) var(--space-5) 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

@media (max-width: 560px) {
  .agenda-sheet__head { padding-left: var(--space-4); }

  .agenda-sheet__body { padding-inline: var(--space-4); }
}

.agenda-form {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}

.agenda-form .alert { margin: 0; }

.agenda-form .alert p { margin: 0; }

/* The title, Notion's way: large, and no box until it is pointed at. */
.agenda-form__title {
  width: 100%;
  min-height: 52px;
  padding: 0.2rem 0.4rem;
  margin-inline: -0.4rem;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text);
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.2;
}

.agenda-form__title::placeholder {
  color: var(--text-3);
  opacity: 1;
}

.agenda-form__title:hover { border-color: var(--line); }

.agenda-form__title:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

/* «Submeter», for a listed item: the first thing it offers. */
.agenda-submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--ink-800);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-3);
}

.agenda-submit__text {
  flex: 1 1 14rem;
  margin: 0;
  color: var(--text-2);
  font-size: var(--step--1);
}

.agenda-submit__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* The properties: the name on the left, a quiet control on the right. */
.agenda-props {
  display: grid;
  gap: 2px;
}

.agenda-prop {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  align-items: center;
  gap: 2px var(--space-3);
  min-width: 0;
  min-height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
}

.agenda-prop__name {
  color: var(--text-3);
  font-size: var(--step--1);
  font-weight: 500;
}

.agenda-prop__value { min-width: 0; }

.agenda-prop .tag-choices { gap: 0 var(--space-1); }

.agenda-prop__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  min-width: 0;
}

.agenda-prop__control {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding: 0.4rem 0.6rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text);
  font: inherit;
  font-size: 0.9375rem;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.agenda-prop__control::placeholder { color: var(--text-3); }

.agenda-prop__control:hover {
  background: var(--ink-800);
  border-color: var(--line);
}

.agenda-prop__control:focus {
  outline: none;
  background: var(--ink-800);
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

select.agenda-prop__control {
  appearance: none;
  padding-right: 2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%238D99AE' stroke-width='2' stroke-linecap='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.6rem center;
  text-overflow: ellipsis;
}

select.agenda-prop__control option,
select.agenda-prop__control optgroup {
  background: var(--ink-700);
  color: var(--text);
}

.agenda-prop__hint {
  grid-column: 2;
  padding-left: 0.6rem;
  color: var(--text-3);
  font-size: 0.75rem;
}

.agenda-prop__text {
  padding: 0.4rem 0.6rem;
  color: var(--text-2);
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
}

/* «Origem» and «Álbum» are links: a thumb's height, the words in its middle. */
a.agenda-prop__text {
  display: flex;
  align-items: center;
  min-height: 44px;
}

/* The level's chips wear the card's clothes: dashed for listed and uncertain. */
.agenda-level--listed .tag-choice__chip,
.agenda-level--tentative .tag-choice__chip { border-style: dashed; }

.agenda-level--tentative .tag-choice__input:checked + .tag-choice__chip {
  border-color: var(--warn);
  color: var(--warn);
}

.agenda-level--confirmed .tag-choice__input:checked + .tag-choice__chip {
  border-color: var(--ok);
  color: var(--ok);
}

.agenda-level--declined .tag-choice__input:checked + .tag-choice__chip {
  border-color: var(--line-strong);
  background: transparent;
  color: var(--text-3);
}

.agenda-level--cancelled .tag-choice__input:checked + .tag-choice__chip { text-decoration: line-through; }

/* The page's body: the notes. */
.agenda-notes {
  display: grid;
  gap: var(--space-2);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.agenda-notes__name {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.agenda-notes__body {
  min-height: 8rem;
  margin-inline: -0.6rem;
  width: calc(100% + 1.2rem);
  padding: 0.5rem 0.6rem;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-2);
  color: var(--text);
  font: inherit;
  line-height: 1.6;
  resize: vertical;
}

.agenda-notes__body:hover { border-color: var(--line); }

.agenda-notes__body:focus {
  outline: none;
  background: var(--ink-800);
  border-color: var(--blue);
  box-shadow: 0 0 0 3px var(--blue-tint);
}

.agenda-notes .field__hint { margin: 0; }

.agenda-notes__links {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
  overflow-wrap: anywhere;
}

.agenda-notes__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* «Guardar»: a plain row under the notes until something changes, then a bar
   held at the bottom of what scrolls, «Alterações por guardar» beside it (the
   studio's own rule). In the sheet and in the day's pane the bar is that box's
   own floor, edge to edge, so nothing shows under it. */
.agenda-form__save {
  position: static;
  margin-top: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.agenda-form__save.is-dirty {
  position: sticky;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--ink-600);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-2);
}

.agenda-sheet__body { --agenda-pad: var(--space-5); }

.agenda-split__form { --agenda-pad: var(--space-4); }

.agenda-sheet .agenda-form__save.is-dirty,
.agenda-split__form .agenda-form__save.is-dirty {
  bottom: 0;
  margin-inline: calc(-1 * var(--agenda-pad));
  padding: var(--space-3) var(--agenda-pad);
  background: var(--ink-700);
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  box-shadow: 0 -12px 20px -14px rgba(0, 0, 0, 0.6);
}

.agenda-split__form .agenda-form__save.is-dirty { background: var(--ink-900); }

@media (max-width: 560px) {
  .agenda-sheet__body { --agenda-pad: var(--space-4); }
}

/* The rarer presses, under a hairline, away from «Guardar». */
.agenda-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding: var(--space-4) 0 var(--space-5);
  border-top: 1px solid var(--line);
}

.agenda-form__foot:not(:has(> button:not([hidden]))) { display: none; }

@media (max-width: 560px) {
  .agenda-prop {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    padding: var(--space-1) 0;
  }

  .agenda-prop__name { padding-left: 0.6rem; }

  .agenda-prop__hint { grid-column: 1; }

  .agenda-form__title { font-size: var(--step-2); }
}

/* The item's own page, for a browser without script. */
.agenda-page { max-width: 46rem; }

/* --- «Horários dos clubes» ------------------------------------------------------------- */

.agenda-slots__club {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.agenda-slots__club .teams { --team-ground: var(--ink-700); }

.agenda-slot.is-paused .media-row__title { color: var(--text-3); }

.agenda-slot__paused { color: var(--warn); }

.agenda-slot .panel__foot .admin__actions form { margin: 0; }

.agenda-slot-fields .field__control {
  min-height: 48px;
  padding-block: 0.6rem;
}

.agenda-slot-fields__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

textarea.agenda-slot-fields__notes { min-height: 5rem; }

.agenda-slots__new > details > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  cursor: pointer;
  list-style: none;
}

.agenda-slots__new > details > summary::-webkit-details-marker { display: none; }

.agenda-slots__new > details > summary h2 {
  margin: 0;
  font-size: var(--step-1);
}

.agenda-slots__new > details[open] > summary { margin-bottom: var(--space-4); }

.agenda-slots__empty { margin-bottom: var(--space-5); }

/* --- «Agenda»: end ---------------------------------------------------------------------- */

/* --- «Ficha do jogo» (047) -----------------------------------------------------
   The game as the album's context, not its subject: one strip the height of
   «Pedir o álbum»'s bar above it, on the same ground and hairline — the two
   teams and the score, the round, the day, the half-time — and «Ficha do
   jogo» to open the goals, cards and line-ups under it. Closed on arrival, so
   the photographs keep the first screen. */
.match {
  margin-top: var(--space-3);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

.match__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  min-height: 56px;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-5);
  list-style: none;
}

summary.match__bar { cursor: pointer; }

summary.match__bar::-webkit-details-marker { display: none; }

.match__score-line {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  min-width: 0;
  font-family: var(--font-display);
  font-weight: 600;
}

.match__team {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

.match__team--away { flex-direction: row-reverse; }

.match__name { overflow-wrap: anywhere; }

.match__result {
  padding: 0.15rem 0.6rem;
  background: var(--ink-600);
  border-radius: var(--r-2);
  font-size: var(--step-1);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.match__result--vs { color: var(--text-3); font-weight: 600; }

.match__dash { margin: 0 0.3rem; color: var(--text-3); font-weight: 400; }

.match__context {
  color: var(--text-2);
  font-size: var(--step--1);
}

/* «Ficha do jogo»: the way in, on the right, a whole outline as the site's
   small buttons have; the chevron turns when it is open. */
.match__toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  margin-left: auto;
  padding: 0 0.875rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-2);
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
  white-space: nowrap;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.match__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}

.match[open] .match__toggle::after { margin-top: 3px; transform: rotate(-135deg); }

summary.match__bar:hover .match__toggle,
.match[open] .match__toggle {
  color: var(--text);
  border-color: var(--text-3);
}

summary.match__bar:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: -2px;
  border-radius: var(--r-3);
}

.match__body {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-4) var(--space-5) var(--space-5);
  border-top: 1px solid var(--line);
}

.match__meta {
  margin: 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.match__events,
.match__lineups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: var(--space-4) var(--space-6);
}

.match__side-name {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
}

.match__none { margin: 0; color: var(--text-3); }

.match__list {
  display: grid;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--text-2);
  font-size: 0.875rem;
}

.match__list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.45rem;
}

.match__list svg { flex: none; color: var(--text); }

.match__min {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.match__note { color: var(--text-3); font-size: 0.75rem; }

/* A card, drawn as one: a small upright rectangle in its colour. */
.match-card {
  display: inline-block;
  flex: none;
  width: 0.6rem;
  height: 0.85rem;
  border-radius: 2px;
  background: #F2C94C;
}

.match-card--red { background: #E5484D; }

.match-card--second_yellow {
  background: linear-gradient(135deg, #F2C94C 0 50%, #E5484D 50% 100%);
}

.match__lineup-part {
  margin: var(--space-3) 0 var(--space-1);
  color: var(--text-3);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.match__players {
  display: grid;
  gap: 0.15rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
}

.match__players li {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
  min-height: 1.9rem;
}

.match__number {
  color: var(--text-3);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.match__player { overflow-wrap: anywhere; }

.match__marks {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.3rem;
  color: var(--text-3);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.match__mark { display: inline-flex; color: var(--text); }

.match__change--in { color: var(--ok); }

/* A phone: the score on its own line, the round and the day under it, and
   «Ficha do jogo» across the strip, a thumb's height. */
@media (max-width: 560px) {
  .match__bar { padding: var(--space-3) var(--space-4); gap: var(--space-2); }

  .match__score-line { width: 100%; font-size: 0.9375rem; }

  .match__toggle {
    justify-content: center;
    width: 100%;
    min-height: 44px;
    margin-left: 0;
  }

  .match__body { padding: var(--space-4); }
}

/* --- «Ficha do jogo» in the panel (admin/album-match) ------------------------- */
.match-import {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0 var(--space-3);
}

.match-import__field {
  flex: 1 1 22rem;
  margin-bottom: var(--space-3);
}

.match-import .btn { margin-top: 1.85rem; }

.match-import__when { margin: 0; }

.match-form__group {
  min-width: 0;
  margin: 0 0 var(--space-6);
  padding: 0;
  border: 0;
}

.match-form__legend {
  margin-bottom: var(--space-3);
  padding: 0;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
}

.match-form__hint { margin: 0 0 var(--space-3); }

.match-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: 0 var(--space-3);
}

.match-grid__wide { grid-column: 1 / -1; }

.match-result {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 0 var(--space-5);
}

.match-result__team {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 5rem;
  gap: 0 var(--space-3);
}

.match-result__half { max-width: 10rem; }

.match-rows {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.match-row {
  display: grid;
  gap: var(--space-2);
  align-items: center;
}

.match-row .field__control { min-height: 44px; }

.match-row--event { grid-template-columns: 5rem minmax(9rem, 1fr) minmax(9rem, 1fr) minmax(10rem, 1.6fr); }

@media (max-width: 760px) {
  .match-row--event {
    grid-template-columns: 4.5rem minmax(0, 1fr);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--line);
  }

  .match-row--event .match-row__cell--player { grid-column: 1 / -1; }
}

.match-lineups-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  gap: 0 var(--space-5);
}

.match-lineups-form__name {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-weight: 600;
}

.match-lineups-form__list { font-variant-numeric: tabular-nums; line-height: 1.6; }

.match-delete { margin: calc(-1 * var(--space-3)) 0 var(--space-6); }

.match-summary__line { margin: 0; color: var(--text-2); }

.match-summary__line strong { margin-right: 0.4rem; color: var(--text); }

/* --- Asked for without the code (relatives albums) ------------------------------
   Under the envelope's field on /pedir/codigo: the other way in, for a family
   whose card never reached them — a hairline, a question, a sentence, and the
   button to the ask with a justification. In the panel, «Sem código» beside
   the ask's status. */
.request-nocode {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

.request-nocode__title {
  margin: 0;
  font-size: var(--step-1);
}

.request-nocode .tiny { margin: 0 0 var(--space-2); }

.request-card__badges {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* «Colar a página»: for when zerozero turns the server away. A quiet line
   under the link's field that opens to four steps and the box to paste in. */
.match-paste {
  margin-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.match-paste__toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  color: var(--text-2);
  font-size: var(--step--1);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.match-paste__toggle::-webkit-details-marker { display: none; }

.match-paste__toggle::after {
  content: "";
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.match-paste[open] .match-paste__toggle::after { margin-top: 3px; transform: rotate(-135deg); }

.match-paste__toggle:hover { color: var(--text); }

.match-paste__steps {
  display: grid;
  gap: 0.35rem;
  margin: 0 0 var(--space-4);
  padding-left: 1.25rem;
  color: var(--text-2);
  font-size: 0.875rem;
}

.match-paste__page {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;
}

/* «Ligar ao zerozero pela Google»: set up once, then a closed line with a
   green «Ligado». The steps, the script to copy, and the address to paste
   back. */
.relay > summary { cursor: pointer; list-style: none; margin-bottom: 0; }

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

.relay[open] > summary { margin-bottom: var(--space-4); }

.relay__lead { margin: 0 0 var(--space-3); color: var(--text-2); }

.relay__steps {
  display: grid;
  gap: 0.4rem;
  margin: 0 0 var(--space-4);
  padding-left: 1.25rem;
  color: var(--text-2);
  font-size: 0.9375rem;
}

.relay__code {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  margin-bottom: var(--space-4);
}

.relay__script {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.75rem;
  line-height: 1.5;
}

.relay__form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0 var(--space-3);
}

.relay__field { flex: 1 1 22rem; margin-bottom: var(--space-3); }

.relay__form .btn { margin-top: 1.85rem; }

/* --- The order of «Álbuns» (admin/albums-order, 048) ---------------------------- */
.album-order__choice { margin: 0 0 var(--space-4); padding: 0; border: 0; }

.album-order__list {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
  padding: 0;
  list-style: none;
}

.album-order__item {
  display: grid;
  grid-template-columns: 1.25rem 4.5rem minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-3);
  min-height: 64px;
  padding: var(--space-2) var(--space-3);
  background: var(--ink-800);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  cursor: grab;
}

.album-order__item.is-dragging { opacity: 0.5; border-color: var(--text-3); }

/* The handle: six dots, the sign of something to drag. */
.album-order__handle {
  width: 10px;
  height: 16px;
  background: radial-gradient(circle, var(--text-3) 1.4px, transparent 1.6px) 0 0 / 5px 5.5px;
}

.album-order__cover {
  width: 4.5rem;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--ink-900);
  border-radius: var(--r-1);
}

.album-order__cover img { width: 100%; height: 100%; object-fit: cover; }

.album-order__text { display: grid; min-width: 0; }

.album-order__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }

.album-order__date { color: var(--text-3); font-size: var(--step--1); }

.album-order__moves { display: inline-flex; gap: var(--space-1); }

.album-order__moves .icon-btn { width: 44px; height: 44px; }

.photo-order { margin: 0; padding: 0; border: 0; }
.album-order__moves .icon-btn:disabled { opacity: 0.3; cursor: default; }

/* Where the sheet came from, when it was read from zerozero (2026-10-19). */
.match__source {
  margin: var(--space-3) 0 0;
  color: var(--text-3);
  font-size: var(--step--1);
}

.match__source a { color: var(--text-2); }

/* The whole album at once (2026-10-19): «Tornar todas públicas», «Dispensar a
   revisão de caras», under the album's counts. */
.album-whole {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: calc(var(--space-2) * -1) 0 var(--space-4);
}

.album-whole__label { color: var(--text-3); font-size: var(--step--1); margin-right: var(--space-1); }

.album-whole form { margin: 0; }

.album-whole .btn { min-height: 40px; }

@media (max-width: 560px) {
  .album-whole .btn { min-height: 44px; }
}

/* An album's grid in the panel, justified (2026-10-19): rows of one height,
   each tile as wide as its photograph (--ratio), so an upright one is whole
   and as tall as the rest instead of cut to a 3:2 frame. The last row keeps
   its height (::after). */
.order-list--justified {
  --row-h: 96px;
  display: flex;
  flex-wrap: wrap;
}

.order-list--justified::after {
  content: "";
  flex: 1000 1 0;
}

.order-list--justified .order-item {
  flex: var(--ratio, 1.5) 1 calc(var(--ratio, 1.5) * var(--row-h));
  min-width: 0;
  aspect-ratio: var(--ratio, 1.5);
}

@media (min-width: 1300px) {
  .order-list--justified { --row-h: 116px; }
}

@media (max-width: 560px) {
  .order-list--justified { --row-h: 80px; }
}

/* /collections' head (2026-10-19): the title, with how many albums and the
   filter (its icon alone) under it, on the left; the groups on the right,
   where the filter was. A row of groups wider than its room slides sideways
   inside it, right-aligned while it fits (the first entry's auto margin, which
   never pushes anything out of reach the way flex-end would). */
.collections-head { flex-wrap: nowrap; align-items: flex-end; }

.collections-head__main { flex: none; }

.collections-head__meta {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.collections-head__meta .tiny { margin: 0; }

.collections-head .group-bar {
  flex: 0 1 auto;
  min-width: 0;
  margin: 0 calc(var(--space-2) * -1) calc(var(--space-2) * -1) 0;
}

.collections-head .group-bar__list { padding: var(--space-2) var(--space-2) var(--space-1); }

.collections-head .group-bar__entry:first-child { margin-inline-start: auto; }

/* The filter as its icon: a round button, its count on its shoulder, and its
   panel opening from the left, under it. */
.album-filter--icon .album-filter__toggle {
  position: relative;
  justify-content: center;
  width: 40px;
  height: 40px;
  min-height: 40px;
  padding: 0;
  border-radius: 50%;
}

.album-filter--icon .album-filter__badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  font-size: 0.6875rem;
}

.album-filter--icon .album-filter__panel { right: auto; left: 0; }

@media (max-width: 700px) {
  .collections-head { flex-wrap: wrap; }

  .collections-head__main { flex: 1 0 100%; }

  .collections-head__meta { justify-content: center; }

  /* The groups the page's width, edge to edge, centred while they fit. */
  .collections-head .group-bar {
    flex: 1 0 100%;
    margin: 0 calc(clamp(1rem, 3.5vw, 2.75rem) * -1);
  }

  .collections-head .group-bar__list { padding-inline: clamp(1rem, 3.5vw, 2.75rem); }

  .collections-head .group-bar__entry:last-child { margin-inline-end: auto; }

  .album-filter--icon .album-filter__toggle { width: 44px; height: 44px; }
}

/* More groups past an edge of the row: that edge fades (app.js). */
.group-bar__list.is-more-after {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 3rem), transparent);
}

.group-bar__list.is-more-before {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 3rem), transparent);
}

.group-bar__list.is-more-before.is-more-after {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(to right, transparent, #000 3rem, #000 calc(100% - 3rem), transparent);
}

/* «Na galeria»: draw it at random (2026-10-19). */
.gallery-draw {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}

.gallery-draw__text { flex: 1 1 18rem; min-width: 0; }

.gallery-draw__title { margin: 0 0 var(--space-1); font-size: 1.125rem; }

.gallery-draw__text .tiny { margin: 0; }

.gallery-draw__count { display: grid; gap: var(--space-1); width: 6.5rem; }

.gallery-draw__count .field__control { min-height: 40px; }

.gallery-draw__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.gallery-draw__actions .btn { min-height: 40px; }

.gallery-draw__undo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: calc(var(--space-2) * -1) 0 var(--space-4);
}

@media (max-width: 560px) {
  .gallery-draw__actions .btn { min-height: 44px; }
}

/* Pins on the order page (049): a pin a finger wide, filled when on. In the
   orders other than «Ordem manual» the list is there for its pins alone: no
   handle, no arrows, no dragging. */
.album-order__pin {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--text-3);
  border: 1px solid var(--line);
  border-radius: 50%;
  cursor: pointer;
}

.album-order__pin:hover { color: var(--text); border-color: var(--text-3); }

.album-order__pin:has(input:checked) { color: var(--ink-900); background: var(--text); border-color: var(--text); }

.album-order__pin:has(input:checked) svg { fill: currentColor; }

.album-order__pin:has(input:focus-visible) { outline: 2px solid var(--text); outline-offset: 2px; }

.album-order:not(.is-manual) .album-order__item {
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  cursor: default;
}

.album-order:not(.is-manual) .album-order__handle,
.album-order:not(.is-manual) .album-order__moves { display: none; }

/* «As melhores» of the gallery (049): a thin gold ring that draws itself once
   round the photograph as its row arrives, a soft glow that stays, and a
   «Top» pill with a gem in the corner the protection flag leaves free. Calm
   on purpose: there are many tops side by side, so nothing loops, pulses or
   twinkles; a mouse over one lifts its glow a little. Still for whoever asked
   for less motion. */
@property --top-d {
  syntax: "<angle>";
  inherits: false;
  initial-value: 360deg;
}

:root {
  --gold-200: #FBEFC2;
  --gold-400: #E2B85A;
}

.tile--top {
  box-shadow: 0 0 16px -4px rgba(226, 184, 90, 0.4);
  transition: box-shadow 400ms var(--ease);
}

.tile--top:hover { box-shadow: 0 0 24px -2px rgba(226, 184, 90, 0.6); }

.tile--top .tile__open::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  padding: 2px;
  border-radius: inherit;
  background: conic-gradient(from -90deg, var(--gold-400) var(--top-d), transparent calc(var(--top-d) + 0.4deg));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}

/* The faint full ring under the drawing one, so the frame is never missing. */
.tile--top .tile__open::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border: 2px solid rgba(226, 184, 90, 0.18);
  border-radius: inherit;
  pointer-events: none;
}

.reveal.is-visible .tile--top .tile__open::after { animation: top-draw 1.3s var(--ease) both; }

@keyframes top-draw {
  from { --top-d: 0deg; }
  to { --top-d: 360deg; }
}

.tile__marks {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}

.tile__top {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(14, 14, 20, 0.72);
  backdrop-filter: blur(6px);
  color: var(--gold-400);
  box-shadow: inset 0 0 0 1.5px var(--gold-400), 0 3px 10px rgba(0, 0, 0, 0.4);
  pointer-events: none;
}

.tile__top svg { width: 14px; height: 14px; fill: currentColor; stroke: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal.is-visible .tile--top .tile__open::after { animation: none; }
  .tile--top { transition: none; }
}

/* The crests of a sport's album over its cover, under a mouse (2026-10-19):
   on a dark veil, crest · score · crest, the clubs' names under them. Only
   where there is a mouse; a finger reads the same clubs under the cover. */
.collection__match { display: none; }

@media (hover: hover) and (pointer: fine) {
  .collection__match {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: clamp(0.75rem, 3cqi, 1.75rem);
    padding: var(--space-4);
    background: radial-gradient(ellipse at center, rgba(20, 21, 31, 0.78), rgba(20, 21, 31, 0.9));
    opacity: 0;
    transition: opacity 220ms var(--ease);
    pointer-events: none;
  }

  .collection--match:hover .collection__match,
  .collection--match:focus-visible .collection__match { opacity: 1; }

  .collection--match:hover .collection__frame img { transform: scale(calc(var(--cover-zoom, 1) * 1.08)); }
}

.collection__frame { container-type: inline-size; }

.collection__club {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  width: min(9rem, 32cqi);
  text-align: center;
  transform: translateY(6px);
  transition: transform 260ms var(--ease);
}

.collection--match:hover .collection__club { transform: none; }

.collection__club-name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.25;
}

.collection__score {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 9cqi, 2.75rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: #fff;
  white-space: nowrap;
}

.collection__dash { margin-inline: 0.2em; color: var(--text-3); }

.collection__score--vs {
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}

.teams--xl { --team-size: 64px; gap: 0.75rem; }

@media (prefers-reduced-motion: reduce) {
  .collection__match,
  .collection__club { transition: none; }
}

/* The home page's recent albums (2026-10-19): four across from 800px, two
   by two below, under the moving wall and over the stream. Smaller cards than
   «Álbuns»: the cover, the clubs and labels, the title, the count and day. */
.home-albums { padding-block: clamp(2.5rem, 6vw, 4.5rem) 0; }

.home-albums__grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
}

.home-albums__grid .collection__summary { display: none; }

.home-albums__grid .collection__body { padding: var(--space-3) var(--space-3) var(--space-4); }

.home-albums__grid .collection__title { font-size: 0.9375rem; }

.home-albums__grid .collection__meta { margin-top: var(--space-2); }

.home-albums__grid .collection__club { width: min(6rem, 36cqi); }

.home-albums__grid .teams--xl { --team-size: 44px; }

.home-albums__grid .collection__club-name { font-size: 0.75rem; }

@media (max-width: 800px) {
  .home-albums__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Pinned (049): a pin in a dark round, on an album's cover corner and on a
   pinned photograph of the gallery; beside the title in the panel's list. */
.pin-mark {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(20, 21, 31, 0.72);
  backdrop-filter: blur(6px);
  color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
}

.pin-mark svg { fill: currentColor; }

.collection__frame > .pin-mark {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 3;
}

.album-list__pin {
  display: inline-flex;
  vertical-align: -2px;
  margin-right: 0.35rem;
  color: var(--text);
}

.album-list__pin svg { fill: currentColor; }

/* A stack (two photographs sharing a column) in a last, short row: the column
   is as wide as its own ratio at the row's height, and the two share that
   height. Each at the row's full height made the column 2× too wide and the
   pair twice the row's height, drawn over what follows (2026-10-19: «a foto
   do álbum fica por cima do footer»). */
.gallery__row--short .gallery__col--stack {
  /* The row's height is its width over --row-ar; the column, its ratio of that.
     Stretched to the row's height, the two share it, the gap between them too. */
  width: calc(100% / var(--row-ar, 3.4) * var(--col-ar, 0.75));
  height: auto;
  align-self: stretch;
}

.gallery__row--short .gallery__col--stack > .tile {
  flex: calc(100 / var(--ar, 1.5)) 1 0%;
  width: 100%;
  height: auto;
  min-height: 0;
  aspect-ratio: auto;
}

/* The viewer's zoom (2026-10-19): the zoomed picture is not cropped to the box
   it fits in, it uses the whole screen, behind the bar and the arrows. The
   gestures are heard on the whole viewer, so they work outside the box too. */
.lightbox { touch-action: none; overflow: hidden; }

.lightbox.is-zoomed .lightbox__stage,
.lightbox.is-zoomed .lightbox__frame { overflow: visible; }

.lightbox.is-zoomed .lightbox__frame { cursor: grab; z-index: 1; }

.lightbox__bar,
.lightbox__foot { position: relative; z-index: 6; }

.lightbox__foot { pointer-events: none; }

.lightbox.is-zoomed .lightbox__foot { opacity: 0.35; }

/* «Pedir o álbum» in the viewer's bar, beside the sharp view and the cross. */
.lightbox__tools { display: flex; align-items: center; gap: var(--space-2); }

.lightbox__request .request-bar { display: contents; }

.lightbox__request .request-bar__actions { display: flex; gap: var(--space-2); }

.lightbox__request form { margin: 0; }

/* The viewer is never wider than the screen, whatever its bar holds: a bar
   that did not fit pushed the whole viewer sideways on a phone, the picture
   half off the screen and the left arrow gone (2026-10-22). */
.lightbox.is-open { grid-template-columns: minmax(0, 1fr); }

.lightbox__bar { min-width: 0; }

.lightbox__tools { flex: none; }

.lightbox__hq,
.lightbox__request .btn { min-height: 40px; white-space: nowrap; }

/* A phone: the bar keeps the count and the cross;
   «Pedir o álbum» goes to the foot, the whole width, where a thumb is. */
@media (max-width: 700px) {
  .lightbox__bar {
    padding: calc(var(--space-2) + env(safe-area-inset-top, 0px)) var(--space-3) var(--space-2);
    gap: var(--space-2);
  }

  .lightbox__credit { display: none; }

  /* No button for the sharp view on a phone: zooming in fetches it by itself
     (draw() in app.js), which is the only way a phone gets to see it anyway. */
  .lightbox__hq { display: none; }

  .lightbox__request {
    position: fixed;
    z-index: 7;
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  }

  .lightbox__request .request-bar__actions,
  .lightbox__request form { display: flex; width: 100%; }

  .lightbox__request .request-bar__actions { gap: var(--space-2); }

  .lightbox__request form { flex: 1; }

  .lightbox__request .btn { width: 100%; min-height: 48px; justify-content: center; }

  /* Room for it under the caption. */
  .lightbox:has(.lightbox__request) .lightbox__foot {
    padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  }

  .lightbox.is-zoomed .lightbox__request { opacity: 0; pointer-events: none; }

  .lightbox__request { transition: opacity var(--base) var(--ease); }
}

/* The size of the panel's photographs (partials/grid-size): a small square, a
   slider, a large one — as in Lightroom. */
.grid-size {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0 0 var(--space-3);
  justify-content: flex-end;
}

.grid-size[hidden] { display: none; }

.grid-size__label { color: var(--text-3); font-size: var(--step--1); margin-right: auto; }

.grid-size__small,
.grid-size__large {
  flex: none;
  border: 1.5px solid var(--text-3);
  border-radius: 2px;
}

.grid-size__small { width: 9px; height: 9px; }

.grid-size__large { width: 16px; height: 16px; }

.grid-size__range { width: min(240px, 46vw); min-height: 44px; accent-color: var(--text); cursor: pointer; }

.admin--studio .photo-grid--justified .photo-card__foot { overflow: hidden; }

/* Zoomed, as photo viewers do it (Google Photos, PhotoSwipe): the controls
   sit on a soft dark band over the picture rather than on boxes of their own,
   and what is pinned to the print's corner — the protection flag — steps out
   of the way until the picture is back at rest, where it belongs to a corner
   again. The blur itself is in the picture and stays. */
.lightbox__bar { transition: background-color var(--base) var(--ease); }

.lightbox.is-zoomed .lightbox__bar {
  background: linear-gradient(180deg, rgba(10, 10, 16, 0.78), rgba(10, 10, 16, 0));
}

.lightbox__request .btn--outline { background: rgba(14, 14, 20, 0.55); }

.pm-rgpd--lb { transition: opacity var(--base) var(--ease); }

.lightbox.is-zoomed .pm-rgpd--lb { opacity: 0; pointer-events: none; }
