/* nextpattern-kit — the shared design: mobile-first, dyslexia-friendly.
   Loaded first; the app's own app.css follows and sets only its accent and
   its own components. Extracted from plate-and-glass.
   Overview first, complexity behind a tap, never everything at once.

   Note on "modern": the refresh here is icons, states and surfaces — a real
   stroke icon set, visible selection, layered hairline elevation. It is
   deliberately NOT the other half of the current idiom: thin grey type, tight
   line height and monochrome minimalism all work against a dyslexic reader,
   so the large text, wide leading and warm colour stay. */

:root {
  color-scheme: light;

  --bg: #fbf7f2;
  --surface: #ffffff;
  --surface-sunken: #f4eee6;
  --text: #2b2622;
  --text-muted: #6f665d;
  --accent: #e08a3c;
  --accent-strong: #c96f22;
  /* Follows the accent, so an app that changes --accent changes this too. */
  --accent-soft: color-mix(in oklab, var(--accent) 15%, transparent);
  --accent-contrast: #ffffff;
  --danger: #c94f3c;
  --danger-bg: #fbe9e5;
  --info: #3c7ae0;
  --info-bg: #e7eefc;
  --warn: #b8892b;
  --warn-bg: #faf0dd;
  --border: #e9e0d5;

  /* Two layers, both tight. One soft 18px blur under every surface was what
     read as 2016 Material: a close contact shadow plus a faint lift gives
     depth without the whole page looking like it is floating. */
  --shadow: 0 1px 2px rgba(60, 45, 20, 0.06), 0 4px 12px rgba(60, 45, 20, 0.05);
  --shadow-lifted: 0 2px 4px rgba(60, 45, 20, 0.07), 0 10px 24px rgba(60, 45, 20, 0.08);

  --radius-lg: 18px;
  --radius-md: 12px;
  --radius-sm: 9px;

  /* Spacing and type scales. New rules use these; the older rules below move
     over where the value is exactly one of them. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --font-sm: 0.85rem;
  --font-base: 1.05rem;
  --font-lg: 1.3rem;
  --font-xl: 1.6rem;

  --nav-height: 68px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Without this the date picker, the radios and the file controls keep
       rendering as light-mode widgets on a dark page. */
    color-scheme: dark;

    --bg: #1c1a17;
    --surface: #262320;
    --surface-sunken: #201d1a;
    --text: #f1ece4;
    --text-muted: #b3a99c;
    --accent: #e79a52;
    --accent-strong: #f0ac6c;
    --accent-contrast: #1c1a17;
    --danger: #e28173;
    --danger-bg: #3a231f;
    --info: #7fa8f2;
    --info-bg: #1f2b3f;
    --warn: #e0b767;
    --warn-bg: #3a2f1a;
    --border: #38332c;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.28);
    --shadow-lifted: 0 2px 4px rgba(0, 0, 0, 0.45), 0 10px 24px rgba(0, 0, 0, 0.35);
  }
}

* {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  letter-spacing: 0.01em;
  padding-bottom: calc(var(--nav-height) + var(--safe-bottom) + 16px);
  /* Suppressed because every tappable thing below has its own press state.
     The grey flash was arriving on top of them and looking like a glitch. */
  -webkit-tap-highlight-color: transparent;
}

a {
  color: inherit;
}

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

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

/* Several things below are display:flex, which would otherwise win over the
   hidden attribute and show an empty error box or an empty photo grid. */
[hidden] {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ---- icons and flags ---- */

/* The sprite itself: present in the document so <use> can reach it, taking up
   no space and reachable by nothing else. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Lucide geometry, coloured by inheritance. The symbols carry no stroke or
   fill attributes precisely so that currentColor reaches them here — which is
   what lets a selected tab tint its icon, something emoji could never do. */
.icon {
  width: 1.25em;
  height: 1.25em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.flag {
  width: 1.45em;
  height: 0.725em; /* every flag here is 2:1 */
  flex: none;
  border-radius: 2px;
  /* Both flags run white to the edge, so on a white card they would dissolve
     without a ring. Inset, so it never changes the box size. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.22);
}

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

.page {
  max-width: 640px;
  margin: 0 auto;
  padding: 20px 16px 12px;
}

.page-title {
  font-size: var(--font-xl);
  font-weight: 700;
  margin: 0 0 12px;
  letter-spacing: -0.01em;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
}

.page-header .page-title {
  margin: 0;
}

/* ---- feed of cards ---- */

.feed {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: var(--space-3);
}

.card {
  display: block;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--border);
  transition: transform 0.12s ease, box-shadow 0.18s ease;
}

.entry-card {
  display: flex;
  align-items: stretch;
  min-height: 84px;
}

.entry-card:active {
  transform: scale(0.985);
  box-shadow: var(--shadow-lifted);
}

/* A thumbnail, not a banner. An entry with no photo renders no element at
   all rather than a placeholder: reserving 220px for a picture that does not
   exist was costing about three anecdotes of screen on every scroll. */
.entry-card-photo {
  /* A fixed square, not a stretched one. With height:auto the image's own
     aspect ratio drove the card, so one portrait photo made its row twice
     the height of every other and the feed stopped scanning evenly. */
  flex: 0 0 76px;
  width: 76px;
  height: 76px;
  align-self: center;
  object-fit: cover;
  border-radius: 10px;
  margin: 10px 0 10px 10px;
  background: var(--surface-sunken);
}

.entry-card-body {
  flex: 1;
  min-width: 0; /* lets long words wrap instead of stretching the card */
  padding: 11px 14px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.entry-card-date {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-weight: 600;
  margin-bottom: 1px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Titles: the thing you scan. Bigger and heavier than the lead under it. */
.entry-card-title {
  margin: 0 0 2px;
  font-size: 1.08rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.entry-card-lead {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---- badges ---- */

.badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 4px 0 16px;
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: var(--font-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
}

.badge-info {
  background: var(--info-bg);
  color: var(--info);
}

.badge-warn {
  background: var(--warn-bg);
  color: var(--warn);
}

.badge-hint {
  font-size: var(--font-sm);
  color: var(--text-muted);
  align-self: center;
}

/* Badges on a card are a footnote, not a headline: the reader needs to know
   a translation is missing, not to be stopped by it. */
.entry-card-body .badge {
  margin-top: 5px;
  align-self: flex-start;
  font-size: 0.7rem;
  padding: 2px 7px;
}

/* ---- empty state ---- */

.empty-state {
  margin-top: 40px;
  padding: 44px 24px;
  text-align: center;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
}

/* A tinted disc around the glyph, rather than a 3.5rem emoji. It reads as a
   deliberate illustration instead of a piece of text that got large. */
.empty-icon,
.centred-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin-bottom: var(--space-4);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.empty-icon .icon,
.centred-icon .icon {
  width: 34px;
  height: 34px;
  stroke-width: 1.75;
}

.centred-icon-warn {
  background: var(--warn-bg);
  color: var(--warn);
}

.empty-title {
  font-size: var(--font-lg);
  font-weight: 700;
  margin: 0 0 8px;
}

.empty-hint {
  color: var(--text-muted);
  margin: 0 0 20px;
}

/* ---- entry detail ---- */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 48px;
  text-decoration: none;
  color: var(--text-muted);
  font-weight: 600;
  margin-bottom: var(--space-2);
}

.back-link .icon {
  width: 1.1em;
  height: 1.1em;
}

.entry-photos {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 -16px 16px;
}

.entry-photo {
  width: 100%;
  max-height: 480px;
  object-fit: cover;
}

.entry-detail {
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 20px;
}

.entry-date {
  font-size: 1rem;
  font-weight: 700;
  color: var(--accent-strong);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 10px;
}

.entry-title {
  margin: 0.2rem 0 0.9rem;
  font-size: var(--font-xl);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--text);
}

.entry-text {
  font-size: 1.2rem;
  line-height: 1.75;
  white-space: pre-wrap;
  margin: 0 0 20px;
}

.entry-author {
  color: var(--text-muted);
  font-size: 1rem;
  margin: 0 0 20px;
}

/* ---- buttons ---- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  min-height: 48px;
  padding: 12px 20px;
  border-radius: var(--radius-md);
  border: none;
  font-size: var(--font-base);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  letter-spacing: 0.01em;
  transition: transform 0.12s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  background: var(--accent);
  color: var(--accent-contrast);
  box-shadow: var(--shadow);
}

.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}

.btn-text-danger {
  background: transparent;
  color: var(--danger);
  border: none;
  font-weight: 600;
}

.btn-large {
  width: 100%;
  padding: 16px 20px;
  font-size: 1.15rem;
}

/* EDGES USE --accent-strong, FILLS USE --accent. An edge carries meaning —
   WCAG wants 3:1 for a control's boundary against the page — and a bright
   accent cannot reach that while staying bright enough to read as its own
   hue. juan-lucas's orange is 2.50:1; plate-and-glass's deep wine clears it
   without trying, which is why these rules shipped painting in --accent and
   nobody saw it until a second app with a light accent arrived.
   TestEdgesPaintInAccentStrongNotAccent keeps it that way. */
.btn:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
.photo-action:focus-within {
  outline: 3px solid var(--accent-strong);
  outline-offset: 2px;
}

/* ---- forms ---- */

.field {
  display: block;
  margin-bottom: 18px;
}

.field-label {
  display: block;
  font-weight: 700;
  margin-bottom: var(--space-2);
  font-size: var(--font-base);
}

.field-input,
.field-textarea {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  color: var(--text);
  font-size: var(--font-base);
  line-height: 1.6;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.field-input:focus,
.field-textarea:focus {
  background: var(--surface);
  border-color: var(--accent-strong);
}

.field-textarea {
  resize: vertical;
}

.field-hint {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--font-sm);
  color: var(--text-muted);
  line-height: 1.5;
}

.entry-form,
.section {
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 20px;
  margin-bottom: var(--space-5);
}

.danger-zone {
  margin: 28px 0 12px;
  text-align: center;
}

.error {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  background: var(--danger-bg);
  color: var(--danger);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-weight: 600;
  margin-bottom: var(--space-4);
}

.error .icon {
  margin-top: 0.2em;
}

/* The "it saved, but" case, for ui.Page.Notice. The kit had the field and no
   rule for it, so an app rendering a notice either styled it itself or — as
   plate-and-glass did — reused .error, which is red and reads as "nothing was
   saved". Same shape as .error so it is scanned the same way, in the
   informational colour because the thing that matters did succeed. */
.notice {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  background: var(--info-bg);
  color: var(--info);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-weight: 600;
  margin-bottom: var(--space-4);
}

.notice .icon {
  margin-top: 0.2em;
}

/* Each language gets its own visible block on the edit screen, so the title
   and the story it belongs to read as one thing rather than four fields. */
.lang-block {
  margin: 0 0 1.4rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
}

.lang-block > legend {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0 0.5rem;
  font-weight: 700;
}

.lang-block .field-input,
.lang-block .field-textarea {
  background: var(--surface);
}

/* ---- photos ---- */

/* Camera and gallery side by side, equal halves. `capture` and `multiple` are
   mutually exclusive on one input, so two controls is not a layout choice. */
.photo-actions {
  display: flex;
  gap: 10px;
}

.photo-action {
  flex: 1;
  min-width: 0;
  font-size: 0.95rem;
  padding: 12px 10px;
  text-align: center;
}

#photoDrop.dragging {
  outline: 3px dashed var(--accent-strong);
  outline-offset: 4px;
  border-radius: var(--radius-lg);
}

/* One grid for both the photos already saved and the ones waiting to upload.
   Seeing them before saving matters more here than anywhere else: you cannot
   tell one blurry thumbnail from another by filename, and a file input shows
   only a count. */
.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 10px;
  margin: 0 0 1.4rem;
}

.photo-cell {
  position: relative;
}

.photo-cell img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-sunken);
}

/* A corner affordance over the picture, not a red bar under it. Nine photos
   used to mean nine full-width Delete buttons, which drowned the grid. */
.photo-remove {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: rgba(20, 16, 12, 0.62);
  color: #fff;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.12s ease;
}

.photo-remove:active {
  transform: scale(0.92);
  background: var(--danger);
}

.photo-remove .icon {
  width: 18px;
  height: 18px;
}

/* ---- settings ---- */

.identity {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 20px;
}

.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  flex: none;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-size: 1.4rem;
  font-weight: 700;
}

.identity-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.identity-name {
  font-size: 1.2rem;
  font-weight: 700;
  line-height: 1.3;
}

.identity-role {
  font-size: 0.9rem;
  color: var(--text-muted);
}

.lang-fieldset {
  border: none;
  padding: 0;
  margin: 0 0 20px;
}

.lang-fieldset > legend {
  padding: 0;
}

.lang-choice-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.lang-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 60px;
  padding: 14px 18px;
  border: 2px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.lang-choice input {
  width: 22px;
  height: 22px;
  flex: none;
  accent-color: var(--accent);
}

.lang-choice .flag {
  width: 2.2em;
  height: 1.1em;
}

.lang-choice-label {
  font-size: 1.15rem;
  font-weight: 600;
}

.lang-choice-selected,
.lang-choice:has(input:checked) {
  border-color: var(--accent-strong);
  background: var(--accent-soft);
}

.signout-form {
  text-align: center;
}

/* ---- centred pages (login, enrol, error) ---- */

.page-centred {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 90vh;
  padding: 24px 16px;
}

.centred-card {
  width: 100%;
  max-width: 420px;
  text-align: center;
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  padding: 36px 24px;
}

.centred-hint {
  color: var(--text-muted);
  margin: 0 0 24px;
  font-size: var(--font-base);
}

/* The error box is flex and left-aligned everywhere else; on these pages it
   is the only thing in a centred card. */
.centred-card .error {
  text-align: left;
  margin: 16px 0 0;
}

/* ---- language switcher ---- */

/* Both options always visible, the current one filled. A single link reading
   "Language: French" is ambiguous — it could mean the page is French or that
   tapping makes it French. Showing both removes the question entirely.

   The flag is the fast visual anchor and the two-letter code is the check on
   it: flag emoji do not render at all on Windows, and a flag alone leaves
   "which English" and "is that selected or available" to inference. */
.lang-switch {
  display: inline-flex;
  gap: var(--space-1);
  padding: var(--space-1);
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
}

.lang-opt {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 40px;
  padding: 0 14px;
  border-radius: 999px;
  font-size: 0.95rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Filled, not merely tinted: the selected one must survive a colour-blind
   reader and a dim screen. */
.lang-opt.on,
.lang-opt:has(input[type="radio"]:checked) {
  background: var(--accent);
  color: var(--accent-contrast);
}

.lang-opt input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* On the new-entry form this is a full-width question, not a header control,
   so the two options split the row and become proper tap targets. */
.lang-pick {
  border: none;
  padding: 0;
  margin: 0 0 1.4rem;
}

.lang-pick > legend {
  padding: 0;
}

.lang-pick .lang-switch {
  display: flex;
  width: 100%;
}

.lang-pick .lang-opt {
  flex: 1;
  min-height: 48px;
}

/* ---- bottom navigation ---- */

.bottomnav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: var(--safe-bottom);
  z-index: 10;
}

.tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--nav-height);
  text-decoration: none;
  color: var(--text-muted);
  transition: color 0.15s ease;
}

/* The pill behind the icon is the selection, and it is the reason the tab bar
   now answers "where am I". Previously nothing marked the current tab at all:
   the only colour change was :active, which lasts exactly as long as your
   finger is on the glass. */
.tab-pill {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 32px;
  border-radius: 999px;
  transition: background-color 0.18s ease;
}

.tab .icon {
  width: 23px;
  height: 23px;
  stroke-width: 1.9;
}

.tab-label {
  font-size: 0.8rem;
  font-weight: 600;
}

.tab.on {
  color: var(--accent-strong);
}

.tab.on .tab-pill {
  background: var(--accent-soft);
}

.tab.on .tab-label {
  font-weight: 700;
}

.tab:active {
  color: var(--accent-strong);
}

/* The Menu tab is a <button>: strip the button chrome so it matches the links. */
button.tab {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

/* ---- the menu, as a bottom sheet (after nextpattern-trip) ----------------
   A bottom sheet rather than a side drawer, because a thumb reaches the
   bottom of a phone and does not reach the top left of one. */
.sheet {
  position: fixed;
  inset: auto 0 0 0;
  width: 100%;
  max-width: none;
  max-height: 88svh;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  border: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 -8px 40px rgba(10, 12, 16, 0.22);
  /* The entry animation: @starting-style is what makes a transition run on
     something that has just appeared, which a popover always has. */
  transition: translate 220ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 160ms ease,
    overlay 220ms allow-discrete, display 220ms allow-discrete;
  translate: 0 0;
  opacity: 1;
}

@starting-style {
  .sheet:popover-open {
    translate: 0 100%;
    opacity: 0.4;
  }
}

.sheet::backdrop {
  background: rgba(8, 10, 14, 0.42);
  transition: opacity 200ms ease, display 200ms allow-discrete;
  opacity: 1;
}

@starting-style {
  .sheet:popover-open::backdrop {
    opacity: 0;
  }
}

/* The grab handle says "this came up from the bottom and can go back down". */
.sheet-handle {
  width: 2.5rem;
  height: 0.25rem;
  border-radius: 999px;
  background: var(--border);
  margin: 12px auto 8px;
}

.sheet-body {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 16px calc(24px + var(--safe-bottom));
}

.sheet-head {
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 4px;
}

.sheet-who {
  margin: 0 0 12px;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.sheet-list {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.sheet-list a,
.sheet-list button {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 52px;
  padding: 10px 8px;
  border: 0;
  border-radius: var(--radius-md);
  background: none;
  color: inherit;
  font: inherit;
  font-size: 1.1rem;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.sheet-list .icon {
  color: var(--text-muted);
}

.sheet-list a:active,
.sheet-list button:active {
  background: var(--surface-sunken);
}

.sheet-close {
  display: block;
  width: 100%;
  margin-top: 20px;
  min-height: 48px;
  padding: var(--space-3);
  border: 0;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  color: var(--text);
  font: inherit;
  font-size: 1.1rem;
  font-weight: 600;
  cursor: pointer;
}

@media (min-width: 700px) {
  .page {
    padding-top: var(--space-6);
  }

  .entry-card-photo {
    flex-basis: 96px;
    width: 96px;
    height: 96px;
  }

  .entry-card {
    min-height: 116px;
  }
}


/* ---- top bar: app name and the language switch, top right (2026-10-27) ----
   juan-lucas's header switch is the house reference; .lang-switch and
   .lang-opt above are its rules. Buttons, not links, because the choice is
   saved; reset their native look so they match juan-lucas's anchors. */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); padding: 12px 16px 4px;
}
.topbar-name { font-size: 1.15rem; font-weight: 700; letter-spacing: -0.01em; }
.topbar .lang-opt { border: 0; font-family: inherit; background: none; }
.topbar .lang-opt.on { background: var(--accent); color: var(--accent-contrast); }
